Commit 87ae0f34 authored by Gus Grubba's avatar Gus Grubba

Merge branch 'master' of https://github.com/mavlink/qgroundcontrol into multiCamera

parents d6b51ece deeaa6e6
...@@ -15,7 +15,7 @@ environment: ...@@ -15,7 +15,7 @@ environment:
install: install:
- git submodule update --init --recursive - git submodule update --init --recursive
- call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 - call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
- set PATH=C:\Qt\Tools\QtCreator\bin;C:\Qt\5.9.3\msvc2015\bin;%PATH% - set PATH=C:\Qt\Tools\QtCreator\bin;C:\Qt\5.11.0\msvc2015\bin;%PATH%
- mkdir %LOCALAPPDATA%\QtProject && copy test\qtlogging.ini %LOCALAPPDATA%\QtProject\ - mkdir %LOCALAPPDATA%\QtProject && copy test\qtlogging.ini %LOCALAPPDATA%\QtProject\
- ps: | - ps: |
Write-Host "Installing GStreamer..." -ForegroundColor Cyan Write-Host "Installing GStreamer..." -ForegroundColor Cyan
...@@ -35,7 +35,7 @@ install: ...@@ -35,7 +35,7 @@ install:
Write-Host "Installed" -ForegroundColor Green Write-Host "Installed" -ForegroundColor Green
build_script: build_script:
- mkdir %SHADOW_BUILD_DIR% && cd %SHADOW_BUILD_DIR% && C:\Qt\5.9.3\msvc2015\bin\qmake -r CONFIG-=debug_and_release CONFIG+=%CONFIG% CONFIG+=WarningsAsErrorsOn %APPVEYOR_BUILD_FOLDER%\qgroundcontrol.pro - mkdir %SHADOW_BUILD_DIR% && cd %SHADOW_BUILD_DIR% && C:\Qt\5.11.0\msvc2015\bin\qmake -r CONFIG-=debug_and_release CONFIG+=%CONFIG% CONFIG+=WarningsAsErrorsOn %APPVEYOR_BUILD_FOLDER%\qgroundcontrol.pro
- cd %SHADOW_BUILD_DIR% && jom - cd %SHADOW_BUILD_DIR% && jom
- if "%CONFIG%" EQU "installer" ( copy %SHADOW_BUILD_DIR%\release\QGroundControl-installer.exe %APPVEYOR_BUILD_FOLDER%\QGroundControl-installer.exe ) - if "%CONFIG%" EQU "installer" ( copy %SHADOW_BUILD_DIR%\release\QGroundControl-installer.exe %APPVEYOR_BUILD_FOLDER%\QGroundControl-installer.exe )
# Generate the source server information to embed in the PDB # Generate the source server information to embed in the PDB
......
...@@ -73,9 +73,9 @@ before_install: ...@@ -73,9 +73,9 @@ before_install:
install: install:
# linux dependencies: qt # linux dependencies: qt
- if [ "${SPEC}" = "linux-g++-64" ]; then - if [ "${SPEC}" = "linux-g++-64" ]; then
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.9.3-gcc_64-min.tar.bz2 && wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.11.0-gcc_64-min.tar.bz2 &&
tar jxf Qt5.9.3-gcc_64-min.tar.bz2 -C /tmp && tar jxf Qt5.11.0-gcc_64-min.tar.bz2 -C /tmp &&
export PATH=/tmp/Qt5.9-gcc_64/5.9.3/gcc_64/bin:$PATH && export PATH=/tmp/Qt5.11-gcc_64/5.11.0/gcc_64/bin:$PATH &&
export DISPLAY=:99.0 && export DISPLAY=:99.0 &&
sh -e /etc/init.d/xvfb start sh -e /etc/init.d/xvfb start
; ;
...@@ -83,8 +83,8 @@ install: ...@@ -83,8 +83,8 @@ install:
# android dependencies: qt, gstreamer, android-ndk # android dependencies: qt, gstreamer, android-ndk
- if [ "${SPEC}" = "android-g++" ]; then - if [ "${SPEC}" = "android-g++" ]; then
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.9.3-android_armv7-min.tar.bz2 && wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.11.0-android_armv7-min.tar.bz2 &&
tar jxf Qt5.9.3-android_armv7-min.tar.bz2 -C /tmp && tar jxf Qt5.11.0-android_armv7-min.tar.bz2 -C /tmp &&
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/gstreamer-1.0-android-armv7-1.5.2.tar.bz2 && wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/gstreamer-1.0-android-armv7-1.5.2.tar.bz2 &&
mkdir -p ${TRAVIS_BUILD_DIR}/gstreamer-1.0-android-armv7-1.5.2 && mkdir -p ${TRAVIS_BUILD_DIR}/gstreamer-1.0-android-armv7-1.5.2 &&
tar jxf gstreamer-1.0-android-armv7-1.5.2.tar.bz2 -C ${TRAVIS_BUILD_DIR}/gstreamer-1.0-android-armv7-1.5.2 && tar jxf gstreamer-1.0-android-armv7-1.5.2.tar.bz2 -C ${TRAVIS_BUILD_DIR}/gstreamer-1.0-android-armv7-1.5.2 &&
...@@ -93,14 +93,14 @@ install: ...@@ -93,14 +93,14 @@ install:
./android-ndk-r10e-linux-x86_64.bin > /dev/null && ./android-ndk-r10e-linux-x86_64.bin > /dev/null &&
export ANDROID_NDK_ROOT=`pwd`/android-ndk-r10e && export ANDROID_NDK_ROOT=`pwd`/android-ndk-r10e &&
export ANDROID_SDK_ROOT=/usr/local/android-sdk && export ANDROID_SDK_ROOT=/usr/local/android-sdk &&
export PATH=/tmp/Qt5.9-android_armv7/5.9.3/android_armv7/bin:`pwd`/android-ndk-r10e:$PATH && echo $PATH export PATH=/tmp/Qt5.11-android_armv7/5.11.0/android_armv7/bin:`pwd`/android-ndk-r10e:$PATH && echo $PATH
; ;
fi fi
# osx dependencies: qt (master builds only: gstreamer, gstreamer-devel) # osx dependencies: qt (master builds only: gstreamer, gstreamer-devel)
- if [ "${SPEC}" = "macx-clang" ]; then - if [ "${SPEC}" = "macx-clang" ]; then
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.9.3-clang_64-min.tar.bz2 && wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.11.0-clang_64-min.tar.bz2 &&
tar jxf Qt5.9.3-clang_64-min.tar.bz2 -C /tmp tar jxf Qt5.11.0-clang_64-min.tar.bz2 -C /tmp
; ;
fi fi
...@@ -123,7 +123,7 @@ install: ...@@ -123,7 +123,7 @@ install:
fi fi
- if [ "${SPEC}" = "macx-clang" ]; then - if [ "${SPEC}" = "macx-clang" ]; then
export QT_DIR=Qt5.9-clang_64/5.9.3/clang_64 && export QT_DIR=Qt5.11-clang_64/5.11.0/clang_64 &&
export QT_QPA_PLATFORM_PLUGIN_PATH=/tmp/$QT_DIR/plugins && export QT_QPA_PLATFORM_PLUGIN_PATH=/tmp/$QT_DIR/plugins &&
export QML2_IMPORT_PATH=/tmp/$QT_DIR/qml && export QML2_IMPORT_PATH=/tmp/$QT_DIR/qml &&
export PATH=/tmp/$QT_DIR/bin:$PATH export PATH=/tmp/$QT_DIR/bin:$PATH
...@@ -161,7 +161,12 @@ before_script: ...@@ -161,7 +161,12 @@ before_script:
script: script:
# run qmake # run qmake
- mkdir ${SHADOW_BUILD_DIR} && cd ${SHADOW_BUILD_DIR} - mkdir ${SHADOW_BUILD_DIR} && cd ${SHADOW_BUILD_DIR}
- qmake -r ${TRAVIS_BUILD_DIR}/qgroundcontrol.pro CONFIG+=${CONFIG} CONFIG+=WarningsAsErrorsOn -spec ${SPEC} # Due to possible bug in Qt 5.11 WarningsAsErrorsOn is off for Linux builds. Hopefully back on once that is resolved.
- if [ "${SPEC}" = "macx-clang" ]; then
qmake -r ${TRAVIS_BUILD_DIR}/qgroundcontrol.pro CONFIG+=${CONFIG} CONFIG+=WarningsAsErrorsOn -spec ${SPEC};
else
qmake -r ${TRAVIS_BUILD_DIR}/qgroundcontrol.pro CONFIG+=${CONFIG} -spec ${SPEC};
fi
# compile # compile
- if [ "${SPEC}" != "macx-ios-clang" ]; then - if [ "${SPEC}" != "macx-ios-clang" ]; then
......
configs: configs:
dev: dev:
'qt_deps_tarball': 'Qt5.9.1-linux-vagrant.tar.bz2' 'qt_deps_tarball': 'Qt5.11.0-gcc_64-min.tar.bz2'
'qt_deps_unpack_parent_dir': '/tmp' 'qt_deps_unpack_parent_dir': '/tmp'
'qt_deps_unpack_dir': '/tmp/Qt5.9-vagrant/5.9.1' 'qt_deps_unpack_dir': '/tmp/Qt5.11-gcc_64/5.11.0'
'qt_deps_bin_unpack_dir': '/tmp/Qt5.9-vagrant/5.9.1/gcc_64/bin' 'qt_deps_bin_unpack_dir': '/tmp/Qt5.11-gcc_64/5.11.0/gcc_64/bin'
'qt_deps_lib_unpack_dir': '/tmp/Qt5.9-vagrant/5.9.1/gcc_64/lib' 'qt_deps_lib_unpack_dir': '/tmp/Qt5.11-gcc_64/5.11.0/gcc_64/lib'
'qt_deps_plugins_unpack_dir': '/tmp/Qt5.9-vagrant/5.9.1/gcc_64/plugins' 'qt_deps_plugins_unpack_dir': '/tmp/Qt5.11-gcc_64/5.11.0/gcc_64/plugins'
'qt_deps_qml_unpack_dir': '/tmp/Qt5.9-vagrant/5.9.1/gcc_64/qml' 'qt_deps_qml_unpack_dir': '/tmp/Qt5.11-gcc_64/5.11.0/gcc_64/qml'
'project_root_dir': '/vagrant' 'project_root_dir': '/vagrant'
...@@ -20,4 +20,4 @@ configs: ...@@ -20,4 +20,4 @@ configs:
'spec': 'linux-g++-64' 'spec': 'linux-g++-64'
'shadow_build_dir': '/vagrant/shadow-build' 'shadow_build_dir': '/vagrant/shadow-build'
'pro': '/vagrant/qgroundcontrol.pro' 'pro': '/vagrant/qgroundcontrol.pro'
'deps_url': 'https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.9.1-linux-vagrant.tar.bz2' 'deps_url': 'https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.11.0-gcc_64-min.tar.bz2'
...@@ -4,6 +4,7 @@ This system is for posting bugs or feature requests ONLY. For questions about ho ...@@ -4,6 +4,7 @@ This system is for posting bugs or feature requests ONLY. For questions about ho
When posting bug reports, include the following informaiton: When posting bug reports, include the following informaiton:
- Ground station operating system. - Ground station operating system.
- QGroundControl version and build (daily, stable, self-built from source, etc.) - QGroundControl version and build (daily, stable, self-built from source, etc.)
- **If you are using a Stable build which is not the latest, first step is to install latest Stable build and try again prior to entering a bug report.**
- Autopilot board: Pixhawk I, Pixhawk Mini, Pixhawk 2, etc. - Autopilot board: Pixhawk I, Pixhawk Mini, Pixhawk 2, etc.
- Autopilot firmware (e.g. PX4, ArduPilot, custom) and version. - Autopilot firmware (e.g. PX4, ArduPilot, custom) and version.
- Exact steps to reproduce the problem. Starting from booting QGroundControl to when the problem occurs. - Exact steps to reproduce the problem. Starting from booting QGroundControl to when the problem occurs.
......
pipeline { pipeline {
agent any agent none
stages { stages {
stage('build') { stage('build') {
parallel { parallel {
stage('Android Release') {
environment {
CCACHE_BASEDIR = "${env.WORKSPACE}"
QGC_CONFIG = 'release'
QMAKE_VER = "5.9.2/android_armv7/bin/qmake"
}
agent {
docker {
image 'mavlink/qgc-build-android:2018-04-14'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
}
}
steps {
sh 'export'
sh 'ccache -z'
sh 'git submodule deinit -f .'
sh 'git clean -ff -x -d .'
sh 'git submodule update --init --recursive --force'
sh 'mkdir build; cd build; ${QT_PATH}/${QMAKE_VER} -r ${WORKSPACE}/qgroundcontrol.pro CONFIG+=${QGC_CONFIG} CONFIG+=WarningsAsErrorsOn'
sh 'cd build; make -j`nproc --all`'
sh 'ccache -s'
}
post {
cleanup {
sh 'git clean -ff -x -d .'
}
}
}
stage('Linux Debug') { stage('Linux Debug') {
environment { environment {
CCACHE_BASEDIR = "${env.WORKSPACE}" CCACHE_BASEDIR = "${env.WORKSPACE}"
...@@ -11,7 +42,7 @@ pipeline { ...@@ -11,7 +42,7 @@ pipeline {
} }
agent { agent {
docker { docker {
image 'mavlink/qgc-build-linux' image 'mavlink/qgc-build-linux:2018-04-14'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw' args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
} }
} }
...@@ -25,7 +56,13 @@ pipeline { ...@@ -25,7 +56,13 @@ pipeline {
sh 'cd build; make -j`nproc --all`' sh 'cd build; make -j`nproc --all`'
sh 'ccache -s' sh 'ccache -s'
} }
post {
cleanup {
sh 'git clean -ff -x -d .'
}
}
} }
stage('Linux Release') { stage('Linux Release') {
environment { environment {
CCACHE_BASEDIR = "${env.WORKSPACE}" CCACHE_BASEDIR = "${env.WORKSPACE}"
...@@ -34,7 +71,7 @@ pipeline { ...@@ -34,7 +71,7 @@ pipeline {
} }
agent { agent {
docker { docker {
image 'mavlink/qgc-build-linux' image 'mavlink/qgc-build-linux:2018-04-14'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw' args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
} }
} }
...@@ -48,7 +85,13 @@ pipeline { ...@@ -48,7 +85,13 @@ pipeline {
sh 'cd build; make -j`nproc --all`' sh 'cd build; make -j`nproc --all`'
sh 'ccache -s' sh 'ccache -s'
} }
post {
cleanup {
sh 'git clean -ff -x -d .'
}
}
} }
stage('OSX Debug') { stage('OSX Debug') {
agent { agent {
node { node {
...@@ -70,7 +113,13 @@ pipeline { ...@@ -70,7 +113,13 @@ pipeline {
sh 'cd build; make -j`sysctl -n hw.ncpu`' sh 'cd build; make -j`sysctl -n hw.ncpu`'
sh 'ccache -s' sh 'ccache -s'
} }
post {
cleanup {
sh 'git clean -ff -x -d .'
}
}
} }
stage('OSX Release') { stage('OSX Release') {
agent { agent {
node { node {
...@@ -79,7 +128,7 @@ pipeline { ...@@ -79,7 +128,7 @@ pipeline {
} }
environment { environment {
CCACHE_BASEDIR = "${env.WORKSPACE}" CCACHE_BASEDIR = "${env.WORKSPACE}"
QGC_CONFIG = 'release' QGC_CONFIG = 'installer'
QMAKE_VER = "5.9.3/clang_64/bin/qmake" QMAKE_VER = "5.9.3/clang_64/bin/qmake"
} }
steps { steps {
...@@ -92,13 +141,27 @@ pipeline { ...@@ -92,13 +141,27 @@ pipeline {
sh 'cd build; make -j`sysctl -n hw.ncpu`' sh 'cd build; make -j`sysctl -n hw.ncpu`'
sh 'ccache -s' sh 'ccache -s'
} }
post {
success {
archiveArtifacts(artifacts: 'build/**/*.dmg', fingerprint: true)
}
cleanup {
sh 'git clean -ff -x -d .'
}
}
} }
} } // parallel
} } // stage('build')
} } // stages
environment { environment {
CCACHE_CPP2 = '1' CCACHE_CPP2 = '1'
CCACHE_DIR = '/tmp/ccache' CCACHE_DIR = '/tmp/ccache'
QT_FATAL_WARNINGS = '1' QT_FATAL_WARNINGS = '1'
} }
options {
buildDiscarder(logRotator(numToKeepStr: '10', artifactDaysToKeepStr: '30'))
timeout(time: 60, unit: 'MINUTES')
}
} }
...@@ -26,12 +26,12 @@ installer { ...@@ -26,12 +26,12 @@ installer {
# We cd to release directory so we can run macdeployqt without a path to the # We cd to release directory so we can run macdeployqt without a path to the
# qgroundcontrol.app file. If you specify a path to the .app file the symbolic # qgroundcontrol.app file. If you specify a path to the .app file the symbolic
# links to plugins will not be created correctly. # links to plugins will not be created correctly.
QMAKE_POST_LINK += && mkdir -p $${DESTDIR}/package
QMAKE_POST_LINK += && cd $${DESTDIR} && $$dirname(QMAKE_QMAKE)/macdeployqt $${TARGET}.app -appstore-compliant -verbose=2 -qmldir=$${BASEDIR}/src QMAKE_POST_LINK += && cd $${DESTDIR} && $$dirname(QMAKE_QMAKE)/macdeployqt $${TARGET}.app -appstore-compliant -verbose=2 -qmldir=$${BASEDIR}/src
# macdeploy is missing some relocations once in a while. "Fix" it: # macdeploy is missing some relocations once in a while. "Fix" it:
QMAKE_POST_LINK += && python $$BASEDIR/tools/osxrelocator.py $${TARGET}.app/Contents @rpath @executable_path/../Frameworks -r > /dev/null 2>&1 QMAKE_POST_LINK += && python $$BASEDIR/tools/osxrelocator.py $${TARGET}.app/Contents @rpath @executable_path/../Frameworks -r > /dev/null 2>&1
# Create package # Create package
QMAKE_POST_LINK += && hdiutil create /tmp/tmp.dmg -ov -volname "$${TARGET}-$${MAC_VERSION}" -fs HFS+ -srcfolder "$${DESTDIR}/" QMAKE_POST_LINK += && hdiutil create /tmp/tmp.dmg -ov -volname "$${TARGET}-$${MAC_VERSION}" -fs HFS+ -srcfolder "$${DESTDIR}/"
QMAKE_POST_LINK += && mkdir -p $${DESTDIR}/package
QMAKE_POST_LINK += && hdiutil convert /tmp/tmp.dmg -format UDBZ -o $${DESTDIR}/package/$${TARGET}.dmg QMAKE_POST_LINK += && hdiutil convert /tmp/tmp.dmg -format UDBZ -o $${DESTDIR}/package/$${TARGET}.dmg
QMAKE_POST_LINK += && rm /tmp/tmp.dmg QMAKE_POST_LINK += && rm /tmp/tmp.dmg
} }
......
...@@ -63,7 +63,9 @@ WindowsBuild { ...@@ -63,7 +63,9 @@ WindowsBuild {
ReleaseBuild: DLL_QT_DEBUGCHAR = "" ReleaseBuild: DLL_QT_DEBUGCHAR = ""
COPY_FILE_LIST = \ COPY_FILE_LIST = \
$$BASEDIR\\libs\\lib\\sdl2\\msvc\\lib\\x86\\SDL2.dll \ $$BASEDIR\\libs\\lib\\sdl2\\msvc\\lib\\x86\\SDL2.dll \
$$BASEDIR\\deploy\\libeay32.dll $$BASEDIR\\deploy\\libeay32.dll \
$$BASEDIR_WIN\\deploy\\libssl32.dll \
$$BASEDIR_WIN\\deploy\\ssleay32.dll
for(COPY_FILE, COPY_FILE_LIST) { for(COPY_FILE, COPY_FILE_LIST) {
QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"$$COPY_FILE\" \"$$DESTDIR_WIN\" QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"$$COPY_FILE\" \"$$DESTDIR_WIN\"
...@@ -102,15 +104,17 @@ LinuxBuild { ...@@ -102,15 +104,17 @@ LinuxBuild {
# QT_INSTALL_LIBS # QT_INSTALL_LIBS
QT_LIB_LIST = \ QT_LIB_LIST = \
libQt5Charts.so.5 \
libQt5Core.so.5 \ libQt5Core.so.5 \
libQt5DBus.so.5 \ libQt5DBus.so.5 \
libQt5Gui.so.5 \ libQt5Gui.so.5 \
libQt5Location.so.5 \ libQt5Location.so.5 \
libQt5Multimedia.so.5 \ libQt5Multimedia.so.5 \
libQt5MultimediaQuick_p.so.5 \ libQt5MultimediaQuick.so.5 \
libQt5Network.so.5 \ libQt5Network.so.5 \
libQt5OpenGL.so.5 \ libQt5OpenGL.so.5 \
libQt5Positioning.so.5 \ libQt5Positioning.so.5 \
libQt5PositioningQuick.so.5 \
libQt5PrintSupport.so.5 \ libQt5PrintSupport.so.5 \
libQt5Qml.so.5 \ libQt5Qml.so.5 \
libQt5Quick.so.5 \ libQt5Quick.so.5 \
......
...@@ -6,83 +6,20 @@ ...@@ -6,83 +6,20 @@
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mavlink/qgroundcontrol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mavlink/qgroundcontrol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Website: <http://qgroundcontrol.com>
## Obtaining source code *QGroundControl* (QGC) is an intuitive and powerful ground control station (GCS) for UAVs.
Source code for QGroundControl is kept on GitHub: https://github.com/mavlink/qgroundcontrol. The primary goal of QGC is ease of use for both first time and professional users.
``` It provides full flight control and mission planning for any MAVLink enabled drone, and vehicle setup for both PX4 and ArduPilot powered UAVs. Instructions for *using QGroundControl* are provided in the [User Manual](https://docs.qgroundcontrol.com/en/) (you may not need them because the UI is very intuitive!)
git clone --recursive https://github.com/mavlink/qgroundcontrol.git
```
Each time you pull new source to your repository you should run `git submodule update` to get the latest submodules as well. Since QGroundControl uses submodules, using the zip file for source download will not work. You must use git.
The source code is [dual-licensed under Apache 2.0 and GPLv3](https://github.com/mavlink/qgroundcontrol/blob/master/COPYING.md). All the code is open-source, so you can contribute and evolve it as you want.
The [Developer Guide](https://dev.qgroundcontrol.com/en/) explains how to [build](https://dev.qgroundcontrol.com/en/getting_started/) and extend QGC.
### User Manual
https://docs.qgroundcontrol.com/en/
### Supported Builds Key Links:
* [Website](http://qgroundcontrol.com) (qgroundcontrol.com)
#### Native Builds * [User Manual](https://docs.qgroundcontrol.com/en/)
QGroundControl builds are supported for OSX, Linux, Windows, iOS and Android. QGroundControl uses [Qt](http://www.qt.io) as its cross-platform support library and uses [QtCreator](http://doc.qt.io/qtcreator/index.html) as its default build environment. * [Developer Guide](https://dev.qgroundcontrol.com/en/)
* [Discussion/Support](https://docs.qgroundcontrol.com/en/Support/Support.html)
* OSX: OSX 10.7 or higher, 64 bit, clang compiler (IMPORTANT: XCode 8 requires a workaround described below) * [Contributing](https://dev.qgroundcontrol.com/en/contribute/)
* Ubuntu: 64 bit, gcc compiler * [License](https://github.com/mavlink/qgroundcontrol/blob/master/COPYING.md)
* Windows: Vista or higher, 32 bit, [Visual Studio 2015 compiler](http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop)
* iOS: 8.0 and higher
* Android: Jelly Bean (4.1) and higher. Standard QGC is built against ndk version 19.
* Qt version: **5.9.3 only**
###### Install QT
You **need to install Qt as described below** instead of using pre-built packages from say, a Linux distribution, because QGroundControl needs access to private Qt headers.
* Download the [Qt installer](http://www.qt.io/download-open-source)
* Make sure to install Qt version **5.9.3**. You will also need to install the Qt Speech package.
* Ubuntu: Set the downloaded file to executable using:`chmod +x`. Install to default location for use with ./qgroundcontrol-start.sh. If you install Qt to a non-default location you will need to modify qgroundcontrol-start.sh in order to run downloaded builds.
* Windows: Make sure to install VS 2015 32 bit package.
###### Install additional packages:
* Ubuntu: sudo apt-get install speech-dispatcher libudev-dev libsdl2-dev libgstreamer1.0-0 gstreamer1.0-plugins-base libgstreamer-plugins-base1.0-dev gstreamer1.0*
* Fedora: sudo dnf install speech-dispatcher SDL2-devel SDL2 systemd-devel
* Arch Linux: pacman -Sy speech-dispatcher
* Windows: [USB Driver](http://www.pixhawk.org/firmware/downloads) to connect to Pixhawk/PX4Flow/3DR Radio
* Android: [Qt Android Setup](http://doc.qt.io/qt-5/androidgs.html)
###### Building using Qt Creator
* Launch Qt Creator and open the `qgroundcontrol.pro` project.
* Select the appropriate kit for your needs:
* OSX: Desktop Qt 5.9.3 clang 64 bit
* Ubuntu: Desktop Qt 5.9.3 GCC bit
* Windows: Desktop Qt 5.9.3 MSVC2015 32bit
* Android: Android for armeabi-v7a (GCC 4.9, Qt 5.9.3)
* Note: iOS builds must be built using xCode: http://doc.qt.io/qt-5/ios-support.html. Use Qt Creator to generate the XCode project (*Run Qmake* from the context menu).
#### Vagrant
A Vagrantfile is provided to build QGroundControl using the [Vagrant](https://www.vagrantup.com/) system. This will produce a native Linux build which can be run in the Vagrant Virtual Machine or on the host machine if it is compatible.
* [Download](https://www.vagrantup.com/downloads.html) Vagrant
* [Install](https://www.vagrantup.com/docs/getting-started/) Vagrant
* From the root directory of the QGroundControl repository run "vagrant up"
* To use the graphical environment run "vagrant reload"
#### Additional build notes for all supported OS
* Warnings as Errors: Specifying `CONFIG+=WarningsAsErrorsOn` will turn all warnings into errors which breaks the build. If you are working on a pull request you plan to submit to github for consideration, you should always run with this setting turned on, since it is required for all pull requests. NOTE: Putting this line into a file called "user_config.pri" in the top-level directory (same directory as `qgroundcontrol.pro`) will set this flag on all builds without interfering with the GIT history.
* Parallel builds: For non Windows builds, you can use the '-j#' option to run parellel builds.
* Location of built files: Individual build file results can be found in the `build_debug` or `build_release` directories. The built executable can be found in the `debug` or `release` directory.
* If you get this error when running qgroundcontrol: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version 'GLIBCXX_3.4.20' not found. You need to either update to the latest gcc, or install the latest libstdc++.6 using: sudo apt-get install libstdc++6.
## Additional functionality
QGroundControl has functionality that is dependent on the operating system and libraries installed by the user. The following sections describe these features, their dependencies, and how to disable/alter them during the build process. These features can be forcibly enabled/disabled by specifying additional values to qmake.
### Opal-RT's RT-LAB simulator
Integration with Opal-RT's RT-LAB simulator can be enabled on Windows by installing RT-LAB 7.2.4. This allows vehicles to be simulated in RT-LAB and communicate directly with QGC on the same computer as if the UAS was actually deployed. This support is enabled by default once the requisite RT-LAB software is installed. Disabling this can be done by adding `DEFINES+=DISABLE_RTLAB` to qmake.
### XBee support
QGroundControl can talk to XBee wireless devices using their proprietary protocol directly on Windows and Linux platforms. This support is not necessary if you're not using XBee devices or aren't using their proprietary protocol. On Windows, the necessary dependencies are included in this repository and no additional steps are required. For Linux, change to the `libs/thirdParty/libxbee` folder and run `make;sudo make install` to install libxbee on your system (uninstalling can be done with a `sudo make uninstall`). `qmake` will automatically detect the library on Linux, so no other work is necessary.
To disable XBee support you may add `DEFINES+=DISABLE_XBEE` to qmake.
### Video Streaming
Check the [Video Streaming](https://github.com/mavlink/qgroundcontrol/tree/master/src/VideoStreaming) directory for further instructions.
...@@ -45,6 +45,7 @@ Vagrant.configure(2) do |config| ...@@ -45,6 +45,7 @@ Vagrant.configure(2) do |config|
$config_shell = <<-'SHELL' $config_shell = <<-'SHELL'
set -e set -e
set -x
export %{build_env} export %{build_env}
export JOBS=$((`cat /proc/cpuinfo | grep -c ^processor`+1)) export JOBS=$((`cat /proc/cpuinfo | grep -c ^processor`+1))
......
...@@ -59,7 +59,15 @@ ...@@ -59,7 +59,15 @@
<!-- Support devices without USB host mode since there are other connection types --> <!-- Support devices without USB host mode since there are other connection types -->
<uses-feature android:name="android.hardware.usb.host" android:required="false"/> <uses-feature android:name="android.hardware.usb.host" android:required="false"/>
<uses-feature android:name="android.hardware.location.GPS" android:required="false" />
<!-- Support devices without Bluetooth since there are other connection types -->
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<!-- Support devices that don't have location services -->
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false"/>
<uses-feature android:name="android.hardware.location" android:required="false"/>
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application. <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features. --> Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES --> <!-- %%INSERT_FEATURES -->
......
buildscript { buildscript {
repositories { repositories {
jcenter() maven {
url "http://repo1.maven.org/maven2"
}
} }
dependencies { dependencies {
...@@ -51,6 +54,10 @@ android { ...@@ -51,6 +54,10 @@ android {
} }
} }
aaptOptions {
cruncherEnabled = false
}
lintOptions { lintOptions {
abortOnError false abortOnError false
} }
......
#!/bin/bash -x #!/bin/bash -x
if [[ $# -eq 0 ]]; then if [ $# -ne 2 ]; then
echo 'MakeQtTravisTarball.sh QtDirectory QtFullVersion QtBaseVersion BuildType' echo 'MakeQtTravisTarball.sh QtDirectory BuildType'
exit 1 exit 1
fi fi
QT_DIRECTORY=$1 QT_DIRECTORY=$1
if [ ! -d ${QT_DIRECTORY} ]; then if [ ! -d ${QT_DIRECTORY} ]; then
echo 'Specify directory for Qt Directory.' echo 'Specify directory for Qt Directory to copy from.'
exit 1 exit 1
fi fi
QT_FULL_VERSION=$2 QT_FULL_VERSION=5.11.0
if [ ! -d ${QT_DIRECTORY}/${QT_FULL_VERSION} ]; then QT_BASE_VERSION=5.11
echo 'Qt version directory not found'
exit 1
fi
QT_BASE_VERSION=$3
QT_BUILD_TYPE=$4 QT_BUILD_TYPE=$2
if [ ! -d ${QT_DIRECTORY}/${QT_FULL_VERSION}/${QT_BUILD_TYPE} ]; then if [ ! -d ${QT_DIRECTORY}/${QT_FULL_VERSION}/${QT_BUILD_TYPE} ]; then
echo 'Qt build type directory not found' echo 'Qt build type directory not found. Specify example: clang_64'
exit 1 exit 1
fi fi
mkdir -p Qt${QT_BASE_VERSION}-${QT_BUILD_TYPE}/${QT_FULL_VERSION}/${QT_BUILD_TYPE} mkdir -p Qt${QT_BASE_VERSION}-${QT_BUILD_TYPE}/${QT_FULL_VERSION}/${QT_BUILD_TYPE}
......
No preview for this file type
...@@ -73,8 +73,12 @@ doinstall: ...@@ -73,8 +73,12 @@ doinstall:
File /r /x ${EXENAME}.pdb /x ${EXENAME}.lib /x ${EXENAME}.exp ${DESTDIR}\*.* File /r /x ${EXENAME}.pdb /x ${EXENAME}.lib /x ${EXENAME}.exp ${DESTDIR}\*.*
File deploy\px4driver.msi File deploy\px4driver.msi
WriteUninstaller $INSTDIR\${EXENAME}-Uninstall.exe WriteUninstaller $INSTDIR\${EXENAME}-Uninstall.exe
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$\"$INSTDIR\${EXENAME}-Uninstall.exe$\"" WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$\"$INSTDIR\${EXENAME}-Uninstall.exe$\""
SetRegView 64
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\${EXENAME}.exe" "DumpCount" 5
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\${EXENAME}.exe" "DumpType" 2
WriteRegExpandStr HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\${EXENAME}.exe" "DumpFolder" "%LOCALAPPDATA%\QGCCrashDumps"
; Only attempt to install the PX4 driver if the version isn't present ; Only attempt to install the PX4 driver if the version isn't present
!define ROOTKEY "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\434608CF2B6E31F0DDBA5C511053F957B55F098E" !define ROOTKEY "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\434608CF2B6E31F0DDBA5C511053F957B55F098E"
...@@ -106,7 +110,8 @@ Section "Uninstall" ...@@ -106,7 +110,8 @@ Section "Uninstall"
RMDir /r /REBOOTOK "$SMPROGRAMS\$StartMenuFolder\" RMDir /r /REBOOTOK "$SMPROGRAMS\$StartMenuFolder\"
SetShellVarContext current SetShellVarContext current
RMDir /r /REBOOTOK "$APPDATA\${ORGNAME}\" RMDir /r /REBOOTOK "$APPDATA\${ORGNAME}\"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\${EXENAME}.exe"
SectionEnd SectionEnd
Section "create Start Menu Shortcuts" Section "create Start Menu Shortcuts"
......
Subproject commit 3ddcbdfcd360c846246d8905d877add3488c8363 Subproject commit 653ac745a57794a38c831f1ff296066a2e09c09b
...@@ -171,6 +171,7 @@ ...@@ -171,6 +171,7 @@
<file alias="APM/BrandImageSub">src/FirmwarePlugin/APM/APMBrandImageSub.png</file> <file alias="APM/BrandImageSub">src/FirmwarePlugin/APM/APMBrandImageSub.png</file>
<file alias="PX4/BrandImage">src/FirmwarePlugin/PX4/PX4BrandImage.png</file> <file alias="PX4/BrandImage">src/FirmwarePlugin/PX4/PX4BrandImage.png</file>
<file alias="subVehicleArrowOpaque.png">src/FlightMap/Images/sub.png</file> <file alias="subVehicleArrowOpaque.png">src/FlightMap/Images/sub.png</file>
<file alias="check.svg">resources/check.svg</file>
</qresource> </qresource>
<qresource prefix="/res"> <qresource prefix="/res">
<file alias="action.svg">resources/action.svg</file> <file alias="action.svg">resources/action.svg</file>
......
...@@ -240,6 +240,7 @@ AndroidBuild || iOSBuild { ...@@ -240,6 +240,7 @@ AndroidBuild || iOSBuild {
QT += \ QT += \
printsupport \ printsupport \
serialport \ serialport \
charts \
} }
contains(DEFINES, QGC_ENABLE_BLUETOOTH) { contains(DEFINES, QGC_ENABLE_BLUETOOTH) {
...@@ -346,6 +347,7 @@ INCLUDEPATH += \ ...@@ -346,6 +347,7 @@ INCLUDEPATH += \
src/QtLocationPlugin \ src/QtLocationPlugin \
src/QtLocationPlugin/QMLControl \ src/QtLocationPlugin/QMLControl \
src/Settings \ src/Settings \
src/Terrain \
src/VehicleSetup \ src/VehicleSetup \
src/ViewWidgets \ src/ViewWidgets \
src/Audio \ src/Audio \
...@@ -391,12 +393,14 @@ HEADERS += \ ...@@ -391,12 +393,14 @@ HEADERS += \
src/api/QGCOptions.h \ src/api/QGCOptions.h \
src/api/QGCSettings.h \ src/api/QGCSettings.h \
src/api/QmlComponentInfo.h \ src/api/QmlComponentInfo.h \
src/comm/HeartbeatTimer.h
SOURCES += \ SOURCES += \
src/api/QGCCorePlugin.cc \ src/api/QGCCorePlugin.cc \
src/api/QGCOptions.cc \ src/api/QGCOptions.cc \
src/api/QGCSettings.cc \ src/api/QGCSettings.cc \
src/api/QmlComponentInfo.cc \ src/api/QmlComponentInfo.cc \
src/comm/HeartbeatTimer.cc
# #
# Unit Test specific configuration goes here (requires full debug build with all plugins) # Unit Test specific configuration goes here (requires full debug build with all plugins)
...@@ -431,7 +435,7 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin { ...@@ -431,7 +435,7 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/MissionManager/SimpleMissionItemTest.h \ src/MissionManager/SimpleMissionItemTest.h \
src/MissionManager/SpeedSectionTest.h \ src/MissionManager/SpeedSectionTest.h \
src/MissionManager/StructureScanComplexItemTest.h \ src/MissionManager/StructureScanComplexItemTest.h \
src/MissionManager/SurveyMissionItemTest.h \ src/MissionManager/SurveyComplexItemTest.h \
src/MissionManager/TransectStyleComplexItemTest.h \ src/MissionManager/TransectStyleComplexItemTest.h \
src/MissionManager/VisualMissionItemTest.h \ src/MissionManager/VisualMissionItemTest.h \
src/qgcunittest/FileDialogTest.h \ src/qgcunittest/FileDialogTest.h \
...@@ -472,7 +476,7 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin { ...@@ -472,7 +476,7 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/MissionManager/SimpleMissionItemTest.cc \ src/MissionManager/SimpleMissionItemTest.cc \
src/MissionManager/SpeedSectionTest.cc \ src/MissionManager/SpeedSectionTest.cc \
src/MissionManager/StructureScanComplexItemTest.cc \ src/MissionManager/StructureScanComplexItemTest.cc \
src/MissionManager/SurveyMissionItemTest.cc \ src/MissionManager/SurveyComplexItemTest.cc \
src/MissionManager/TransectStyleComplexItemTest.cc \ src/MissionManager/TransectStyleComplexItemTest.cc \
src/MissionManager/VisualMissionItemTest.cc \ src/MissionManager/VisualMissionItemTest.cc \
src/qgcunittest/FileDialogTest.cc \ src/qgcunittest/FileDialogTest.cc \
...@@ -511,6 +515,7 @@ HEADERS += \ ...@@ -511,6 +515,7 @@ HEADERS += \
src/Joystick/Joystick.h \ src/Joystick/Joystick.h \
src/Joystick/JoystickManager.h \ src/Joystick/JoystickManager.h \
src/JsonHelper.h \ src/JsonHelper.h \
src/KMLFileHelper.h \
src/LogCompressor.h \ src/LogCompressor.h \
src/MG.h \ src/MG.h \
src/MissionManager/CameraCalc.h \ src/MissionManager/CameraCalc.h \
...@@ -544,7 +549,7 @@ HEADERS += \ ...@@ -544,7 +549,7 @@ HEADERS += \
src/MissionManager/Section.h \ src/MissionManager/Section.h \
src/MissionManager/SpeedSection.h \ src/MissionManager/SpeedSection.h \
src/MissionManager/StructureScanComplexItem.h \ src/MissionManager/StructureScanComplexItem.h \
src/MissionManager/SurveyMissionItem.h \ src/MissionManager/SurveyComplexItem.h \
src/MissionManager/TransectStyleComplexItem.h \ src/MissionManager/TransectStyleComplexItem.h \
src/MissionManager/VisualMissionItem.h \ src/MissionManager/VisualMissionItem.h \
src/PositionManager/PositionManager.h \ src/PositionManager/PositionManager.h \
...@@ -567,7 +572,6 @@ HEADERS += \ ...@@ -567,7 +572,6 @@ HEADERS += \
src/QmlControls/AppMessages.h \ src/QmlControls/AppMessages.h \
src/QmlControls/CoordinateVector.h \ src/QmlControls/CoordinateVector.h \
src/QmlControls/EditPositionDialogController.h \ src/QmlControls/EditPositionDialogController.h \
src/QmlControls/MavlinkQmlSingleton.h \
src/QmlControls/ParameterEditorController.h \ src/QmlControls/ParameterEditorController.h \
src/QmlControls/QGCFileDialogController.h \ src/QmlControls/QGCFileDialogController.h \
src/QmlControls/QGCImageProvider.h \ src/QmlControls/QGCImageProvider.h \
...@@ -586,7 +590,8 @@ HEADERS += \ ...@@ -586,7 +590,8 @@ HEADERS += \
src/Settings/SettingsManager.h \ src/Settings/SettingsManager.h \
src/Settings/UnitsSettings.h \ src/Settings/UnitsSettings.h \
src/Settings/VideoSettings.h \ src/Settings/VideoSettings.h \
src/Terrain.h \ src/Terrain/TerrainQuery.h \
src/TerrainTile.h \
src/Vehicle/MAVLinkLogManager.h \ src/Vehicle/MAVLinkLogManager.h \
src/VehicleSetup/JoystickConfigController.h \ src/VehicleSetup/JoystickConfigController.h \
src/comm/LinkConfiguration.h \ src/comm/LinkConfiguration.h \
...@@ -707,6 +712,7 @@ SOURCES += \ ...@@ -707,6 +712,7 @@ SOURCES += \
src/Joystick/Joystick.cc \ src/Joystick/Joystick.cc \
src/Joystick/JoystickManager.cc \ src/Joystick/JoystickManager.cc \
src/JsonHelper.cc \ src/JsonHelper.cc \
src/KMLFileHelper.cc \
src/LogCompressor.cc \ src/LogCompressor.cc \
src/MissionManager/CameraCalc.cc \ src/MissionManager/CameraCalc.cc \
src/MissionManager/CameraSection.cc \ src/MissionManager/CameraSection.cc \
...@@ -738,7 +744,7 @@ SOURCES += \ ...@@ -738,7 +744,7 @@ SOURCES += \
src/MissionManager/SimpleMissionItem.cc \ src/MissionManager/SimpleMissionItem.cc \
src/MissionManager/SpeedSection.cc \ src/MissionManager/SpeedSection.cc \
src/MissionManager/StructureScanComplexItem.cc \ src/MissionManager/StructureScanComplexItem.cc \
src/MissionManager/SurveyMissionItem.cc \ src/MissionManager/SurveyComplexItem.cc \
src/MissionManager/TransectStyleComplexItem.cc \ src/MissionManager/TransectStyleComplexItem.cc \
src/MissionManager/VisualMissionItem.cc \ src/MissionManager/VisualMissionItem.cc \
src/PositionManager/PositionManager.cpp \ src/PositionManager/PositionManager.cpp \
...@@ -778,7 +784,8 @@ SOURCES += \ ...@@ -778,7 +784,8 @@ SOURCES += \
src/Settings/SettingsManager.cc \ src/Settings/SettingsManager.cc \
src/Settings/UnitsSettings.cc \ src/Settings/UnitsSettings.cc \
src/Settings/VideoSettings.cc \ src/Settings/VideoSettings.cc \
src/Terrain.cc \ src/Terrain/TerrainQuery.cc \
src/TerrainTile.cc\
src/Vehicle/MAVLinkLogManager.cc \ src/Vehicle/MAVLinkLogManager.cc \
src/VehicleSetup/JoystickConfigController.cc \ src/VehicleSetup/JoystickConfigController.cc \
src/comm/LinkConfiguration.cc \ src/comm/LinkConfiguration.cc \
...@@ -941,6 +948,7 @@ APMFirmwarePlugin { ...@@ -941,6 +948,7 @@ APMFirmwarePlugin {
src/AutoPilotPlugins/APM/APMCompassCal.h \ src/AutoPilotPlugins/APM/APMCompassCal.h \
src/AutoPilotPlugins/APM/APMFlightModesComponent.h \ src/AutoPilotPlugins/APM/APMFlightModesComponent.h \
src/AutoPilotPlugins/APM/APMFlightModesComponentController.h \ src/AutoPilotPlugins/APM/APMFlightModesComponentController.h \
src/AutoPilotPlugins/APM/APMHeliComponent.h \
src/AutoPilotPlugins/APM/APMLightsComponent.h \ src/AutoPilotPlugins/APM/APMLightsComponent.h \
src/AutoPilotPlugins/APM/APMSubFrameComponent.h \ src/AutoPilotPlugins/APM/APMSubFrameComponent.h \
src/AutoPilotPlugins/APM/APMPowerComponent.h \ src/AutoPilotPlugins/APM/APMPowerComponent.h \
...@@ -966,6 +974,7 @@ APMFirmwarePlugin { ...@@ -966,6 +974,7 @@ APMFirmwarePlugin {
src/AutoPilotPlugins/APM/APMCompassCal.cc \ src/AutoPilotPlugins/APM/APMCompassCal.cc \
src/AutoPilotPlugins/APM/APMFlightModesComponent.cc \ src/AutoPilotPlugins/APM/APMFlightModesComponent.cc \
src/AutoPilotPlugins/APM/APMFlightModesComponentController.cc \ src/AutoPilotPlugins/APM/APMFlightModesComponentController.cc \
src/AutoPilotPlugins/APM/APMHeliComponent.cc \
src/AutoPilotPlugins/APM/APMLightsComponent.cc \ src/AutoPilotPlugins/APM/APMLightsComponent.cc \
src/AutoPilotPlugins/APM/APMSubFrameComponent.cc \ src/AutoPilotPlugins/APM/APMSubFrameComponent.cc \
src/AutoPilotPlugins/APM/APMPowerComponent.cc \ src/AutoPilotPlugins/APM/APMPowerComponent.cc \
...@@ -1054,7 +1063,7 @@ HEADERS += \ ...@@ -1054,7 +1063,7 @@ HEADERS += \
src/FactSystem/FactGroup.h \ src/FactSystem/FactGroup.h \
src/FactSystem/FactMetaData.h \ src/FactSystem/FactMetaData.h \
src/FactSystem/FactSystem.h \ src/FactSystem/FactSystem.h \
src/FactSystem/FactValidator.h \ src/FactSystem/FactValueSliderListModel.h \
src/FactSystem/ParameterManager.h \ src/FactSystem/ParameterManager.h \
src/FactSystem/SettingsFact.h \ src/FactSystem/SettingsFact.h \
...@@ -1064,7 +1073,7 @@ SOURCES += \ ...@@ -1064,7 +1073,7 @@ SOURCES += \
src/FactSystem/FactGroup.cc \ src/FactSystem/FactGroup.cc \
src/FactSystem/FactMetaData.cc \ src/FactSystem/FactMetaData.cc \
src/FactSystem/FactSystem.cc \ src/FactSystem/FactSystem.cc \
src/FactSystem/FactValidator.cc \ src/FactSystem/FactValueSliderListModel.cc \
src/FactSystem/ParameterManager.cc \ src/FactSystem/ParameterManager.cc \
src/FactSystem/SettingsFact.cc \ src/FactSystem/SettingsFact.cc \
......
...@@ -9,10 +9,11 @@ ...@@ -9,10 +9,11 @@
<file alias="GPSRTKIndicator.qml">src/ui/toolbar/GPSRTKIndicator.qml</file> <file alias="GPSRTKIndicator.qml">src/ui/toolbar/GPSRTKIndicator.qml</file>
<file alias="MessageIndicator.qml">src/ui/toolbar/MessageIndicator.qml</file> <file alias="MessageIndicator.qml">src/ui/toolbar/MessageIndicator.qml</file>
<file alias="ModeIndicator.qml">src/ui/toolbar/ModeIndicator.qml</file> <file alias="ModeIndicator.qml">src/ui/toolbar/ModeIndicator.qml</file>
<file alias="VTOLModeIndicator.qml">src/ui/toolbar/VTOLModeIndicator.qml</file> <file alias="VTOLModeIndicator.qml">src/ui/toolbar/VTOLModeIndicator.qml</file>
<file alias="RCRSSIIndicator.qml">src/ui/toolbar/RCRSSIIndicator.qml</file> <file alias="RCRSSIIndicator.qml">src/ui/toolbar/RCRSSIIndicator.qml</file>
<file alias="TelemetryRSSIIndicator.qml">src/ui/toolbar/TelemetryRSSIIndicator.qml</file> <file alias="TelemetryRSSIIndicator.qml">src/ui/toolbar/TelemetryRSSIIndicator.qml</file>
<file alias="JoystickIndicator.qml">src/ui/toolbar/JoystickIndicator.qml</file> <file alias="JoystickIndicator.qml">src/ui/toolbar/JoystickIndicator.qml</file>
<file alias="LinkIndicator.qml">src/ui/toolbar/LinkIndicator.qml</file>
</qresource> </qresource>
<qresource prefix="/qml"> <qresource prefix="/qml">
<file alias="CorridorScanEditor.qml">src/PlanView/CorridorScanEditor.qml</file> <file alias="CorridorScanEditor.qml">src/PlanView/CorridorScanEditor.qml</file>
...@@ -85,7 +86,12 @@ ...@@ -85,7 +86,12 @@
<file alias="QGroundControl/Controls/PageView.qml">src/QmlControls/PageView.qml</file> <file alias="QGroundControl/Controls/PageView.qml">src/QmlControls/PageView.qml</file>
<file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file> <file alias="QGroundControl/Controls/ParameterEditor.qml">src/QmlControls/ParameterEditor.qml</file>
<file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file> <file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file>
<file alias="QGroundControl/Controls/PIDTuning.qml">src/QmlControls/PIDTuning.qml</file>
<file alias="QGroundControl/Controls/PlanToolBar.qml">src/PlanView/PlanToolBar.qml</file> <file alias="QGroundControl/Controls/PlanToolBar.qml">src/PlanView/PlanToolBar.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckButton.qml">src/QmlControls/PreFlightCheckButton.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckGroup.qml">src/QmlControls/PreFlightCheckGroup.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckList.qml">src/QmlControls/PreFlightCheckList.qml</file>
<file alias="QGroundControl/Controls/PreFlightCheckModel.qml">src/QmlControls/PreFlightCheckModel.qml</file>
<file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file> <file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file>
<file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file> <file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file>
<file alias="QGroundControl/Controls/QGCColoredImage.qml">src/QmlControls/QGCColoredImage.qml</file> <file alias="QGroundControl/Controls/QGCColoredImage.qml">src/QmlControls/QGCColoredImage.qml</file>
...@@ -118,13 +124,14 @@ ...@@ -118,13 +124,14 @@
<file alias="QGroundControl/Controls/RallyPointMapVisuals.qml">src/PlanView/RallyPointMapVisuals.qml</file> <file alias="QGroundControl/Controls/RallyPointMapVisuals.qml">src/PlanView/RallyPointMapVisuals.qml</file>
<file alias="QGroundControl/Controls/RCChannelMonitor.qml">src/QmlControls/RCChannelMonitor.qml</file> <file alias="QGroundControl/Controls/RCChannelMonitor.qml">src/QmlControls/RCChannelMonitor.qml</file>
<file alias="QGroundControl/Controls/RoundButton.qml">src/QmlControls/RoundButton.qml</file> <file alias="QGroundControl/Controls/RoundButton.qml">src/QmlControls/RoundButton.qml</file>
<file alias="QGroundControl/Controls/SectionHeader.qml">src/PlanView/SectionHeader.qml</file> <file alias="QGroundControl/Controls/SectionHeader.qml">src/QmlControls/SectionHeader.qml</file>
<file alias="QGroundControl/Controls/SetupPage.qml">src/AutoPilotPlugins/Common/SetupPage.qml</file> <file alias="QGroundControl/Controls/SetupPage.qml">src/AutoPilotPlugins/Common/SetupPage.qml</file>
<file alias="QGroundControl/Controls/SignalStrength.qml">src/ui/toolbar/SignalStrength.qml</file> <file alias="QGroundControl/Controls/SignalStrength.qml">src/ui/toolbar/SignalStrength.qml</file>
<file alias="QGroundControl/Controls/SimpleItemMapVisual.qml">src/PlanView/SimpleItemMapVisual.qml</file> <file alias="QGroundControl/Controls/SimpleItemMapVisual.qml">src/PlanView/SimpleItemMapVisual.qml</file>
<file alias="QGroundControl/Controls/SliderSwitch.qml">src/QmlControls/SliderSwitch.qml</file> <file alias="QGroundControl/Controls/SliderSwitch.qml">src/QmlControls/SliderSwitch.qml</file>
<file alias="QGroundControl/Controls/SubMenuButton.qml">src/QmlControls/SubMenuButton.qml</file> <file alias="QGroundControl/Controls/SubMenuButton.qml">src/QmlControls/SubMenuButton.qml</file>
<file alias="QGroundControl/Controls/SurveyMapVisual.qml">src/PlanView/SurveyMapVisual.qml</file> <file alias="QGroundControl/Controls/SurveyMapVisual.qml">src/PlanView/SurveyMapVisual.qml</file>
<file alias="QGroundControl/Controls/TransectStyleComplexItemStats.qml">src/PlanView/TransectStyleComplexItemStats.qml</file>
<file alias="QGroundControl/Controls/ToolStrip.qml">src/QmlControls/ToolStrip.qml</file> <file alias="QGroundControl/Controls/ToolStrip.qml">src/QmlControls/ToolStrip.qml</file>
<file alias="QGroundControl/Controls/VehicleRotationCal.qml">src/QmlControls/VehicleRotationCal.qml</file> <file alias="QGroundControl/Controls/VehicleRotationCal.qml">src/QmlControls/VehicleRotationCal.qml</file>
<file alias="QGroundControl/Controls/VehicleSummaryRow.qml">src/QmlControls/VehicleSummaryRow.qml</file> <file alias="QGroundControl/Controls/VehicleSummaryRow.qml">src/QmlControls/VehicleSummaryRow.qml</file>
...@@ -137,6 +144,7 @@ ...@@ -137,6 +144,7 @@
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file> <file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldGrid.qml">src/FactSystem/FactControls/FactTextFieldGrid.qml</file> <file alias="QGroundControl/FactControls/FactTextFieldGrid.qml">src/FactSystem/FactControls/FactTextFieldGrid.qml</file>
<file alias="QGroundControl/FactControls/FactTextFieldRow.qml">src/FactSystem/FactControls/FactTextFieldRow.qml</file> <file alias="QGroundControl/FactControls/FactTextFieldRow.qml">src/FactSystem/FactControls/FactTextFieldRow.qml</file>
<file alias="QGroundControl/FactControls/FactValueSlider.qml">src/FactSystem/FactControls/FactValueSlider.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file> <file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="QGroundControl/FlightDisplay/FlightDisplayViewMap.qml">src/FlightDisplay/FlightDisplayViewMap.qml</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayViewMap.qml">src/FlightDisplay/FlightDisplayViewMap.qml</file>
...@@ -147,6 +155,12 @@ ...@@ -147,6 +155,12 @@
<file alias="QGroundControl/FlightDisplay/GuidedActionsController.qml">src/FlightDisplay/GuidedActionsController.qml</file> <file alias="QGroundControl/FlightDisplay/GuidedActionsController.qml">src/FlightDisplay/GuidedActionsController.qml</file>
<file alias="QGroundControl/FlightDisplay/GuidedAltitudeSlider.qml">src/FlightDisplay/GuidedAltitudeSlider.qml</file> <file alias="QGroundControl/FlightDisplay/GuidedAltitudeSlider.qml">src/FlightDisplay/GuidedAltitudeSlider.qml</file>
<file alias="QGroundControl/FlightDisplay/MultiVehicleList.qml">src/FlightDisplay/MultiVehicleList.qml</file> <file alias="QGroundControl/FlightDisplay/MultiVehicleList.qml">src/FlightDisplay/MultiVehicleList.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightBatteryCheck.qml">src/FlightDisplay/PreFlightBatteryCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/BuiltInPreFlightCheckModel.qml">src/FlightDisplay/BuiltInPreFlightCheckModel.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightGPSCheck.qml">src/FlightDisplay/PreFlightGPSCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightRCCheck.qml">src/FlightDisplay/PreFlightRCCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightSensorsHealthCheck.qml">src/FlightDisplay/PreFlightSensorsHealthCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/PreFlightSoundCheck.qml">src/FlightDisplay/PreFlightSoundCheck.qml</file>
<file alias="QGroundControl/FlightDisplay/qmldir">src/FlightDisplay/qmldir</file> <file alias="QGroundControl/FlightDisplay/qmldir">src/FlightDisplay/qmldir</file>
<file alias="QGroundControl/FlightMap/CameraTriggerIndicator.qml">src/FlightMap/MapItems/CameraTriggerIndicator.qml</file> <file alias="QGroundControl/FlightMap/CameraTriggerIndicator.qml">src/FlightMap/MapItems/CameraTriggerIndicator.qml</file>
<file alias="QGroundControl/FlightMap/CenterMapDropButton.qml">src/FlightMap/Widgets/CenterMapDropButton.qml</file> <file alias="QGroundControl/FlightMap/CenterMapDropButton.qml">src/FlightMap/Widgets/CenterMapDropButton.qml</file>
...@@ -221,8 +235,10 @@ ...@@ -221,8 +235,10 @@
<file alias="USBBoardInfo.json">src/comm/USBBoardInfo.json</file> <file alias="USBBoardInfo.json">src/comm/USBBoardInfo.json</file>
<file alias="Vehicle/BatteryFact.json">src/Vehicle/BatteryFact.json</file> <file alias="Vehicle/BatteryFact.json">src/Vehicle/BatteryFact.json</file>
<file alias="Vehicle/ClockFact.json">src/Vehicle/ClockFact.json</file> <file alias="Vehicle/ClockFact.json">src/Vehicle/ClockFact.json</file>
<file alias="Vehicle/DistanceSensorFact.json">src/Vehicle/DistanceSensorFact.json</file>
<file alias="Vehicle/GPSFact.json">src/Vehicle/GPSFact.json</file> <file alias="Vehicle/GPSFact.json">src/Vehicle/GPSFact.json</file>
<file alias="Vehicle/GPSRTKFact.json">src/Vehicle/GPSRTKFact.json</file> <file alias="Vehicle/GPSRTKFact.json">src/Vehicle/GPSRTKFact.json</file>
<file alias="Vehicle/SetpointFact.json">src/Vehicle/SetpointFact.json</file>
<file alias="Vehicle/SubmarineFact.json">src/Vehicle/SubmarineFact.json</file> <file alias="Vehicle/SubmarineFact.json">src/Vehicle/SubmarineFact.json</file>
<file alias="Vehicle/TemperatureFact.json">src/Vehicle/TemperatureFact.json</file> <file alias="Vehicle/TemperatureFact.json">src/Vehicle/TemperatureFact.json</file>
<file alias="Vehicle/VehicleFact.json">src/Vehicle/VehicleFact.json</file> <file alias="Vehicle/VehicleFact.json">src/Vehicle/VehicleFact.json</file>
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 72 72"
style="enable-background:new 0 0 72 72;"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="check.svg"><metadata
id="metadata3416"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs3414"><linearGradient
id="linearGradient4141"
osb:paint="solid"><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4143" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4141"
id="linearGradient4145"
x1="48.508473"
y1="58.423729"
x2="79.322032"
y2="58.423729"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.8414091,0,0,2.2407508,-82.18242,-94.289127)" /></defs><sodipodi:namedview
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1056"
id="namedview3412"
showgrid="false"
inkscape:zoom="3.2777778"
inkscape:cx="-54.305085"
inkscape:cy="36"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" /><style
type="text/css"
id="style3406">
.st0{fill:#66BD59;stroke:#FFFFFF;stroke-width:5;stroke-miterlimit:10;}
.st1{fill:none;stroke:#FFFFFF;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style><polyline
class="st1"
points="55.1,19.8 30.2,52.2 16.9,36.5 "
id="polyline3410"
transform="matrix(0.85559226,0,0,0.85559226,5.1269823,8.2041673)"
style="fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10" /><style
id="style3419"
type="text/css">
.st0{fill:none;stroke:#FFFFFF;stroke-width:3;stroke-miterlimit:10;}
.st1{fill:none;stroke:#FFFFFF;stroke-width:8;stroke-miterlimit:10;}
.st2{fill:#FFFFFF;}
</style><circle
style="fill:none;stroke:url(#linearGradient4145);stroke-width:3.25963402;stroke-miterlimit:4;stroke-dasharray:none"
id="path3339"
cx="35.5117"
cy="36.62389"
r="28.370182" /></svg>
\ No newline at end of file
...@@ -70,8 +70,7 @@ void GeoTagController::startTagging(void) ...@@ -70,8 +70,7 @@ void GeoTagController::startTagging(void)
QDir imageDirectory = QDir(_worker.imageDirectory()); QDir imageDirectory = QDir(_worker.imageDirectory());
if(!imageDirectory.exists()) { if(!imageDirectory.exists()) {
_errorMessage = tr("Cannot find the image directory"); _setErrorMessage(tr("Cannot find the image directory"));
emit errorMessageChanged(_errorMessage);
return; return;
} }
if(_worker.saveDirectory() == "") { if(_worker.saveDirectory() == "") {
...@@ -83,23 +82,20 @@ void GeoTagController::startTagging(void) ...@@ -83,23 +82,20 @@ void GeoTagController::startTagging(void)
msgBox.setWindowModality(Qt::ApplicationModal); msgBox.setWindowModality(Qt::ApplicationModal);
msgBox.addButton(tr("Replace"), QMessageBox::ActionRole); msgBox.addButton(tr("Replace"), QMessageBox::ActionRole);
if (msgBox.exec() == QMessageBox::Cancel) { if (msgBox.exec() == QMessageBox::Cancel) {
_errorMessage = tr("Images have already been tagged"); _setErrorMessage(tr("Images have already been tagged"));
emit errorMessageChanged(_errorMessage);
return; return;
} }
QDir oldTaggedFolder = QDir(_worker.imageDirectory() + "/TAGGED"); QDir oldTaggedFolder = QDir(_worker.imageDirectory() + "/TAGGED");
oldTaggedFolder.removeRecursively(); oldTaggedFolder.removeRecursively();
if(!imageDirectory.mkdir(_worker.imageDirectory() + "/TAGGED")) { if(!imageDirectory.mkdir(_worker.imageDirectory() + "/TAGGED")) {
_errorMessage = tr("Couldn't replace the previously tagged images"); _setErrorMessage(tr("Couldn't replace the previously tagged images"));
emit errorMessageChanged(_errorMessage);
return; return;
} }
} }
} else { } else {
QDir saveDirectory = QDir(_worker.saveDirectory()); QDir saveDirectory = QDir(_worker.saveDirectory());
if(!saveDirectory.exists()) { if(!saveDirectory.exists()) {
_errorMessage = tr("Cannot find the save directory"); _setErrorMessage(tr("Cannot find the save directory"));
emit errorMessageChanged(_errorMessage);
return; return;
} }
saveDirectory.setFilter(QDir::Files | QDir::Readable | QDir::NoSymLinks | QDir::Writable); saveDirectory.setFilter(QDir::Files | QDir::Readable | QDir::NoSymLinks | QDir::Writable);
...@@ -115,15 +111,13 @@ void GeoTagController::startTagging(void) ...@@ -115,15 +111,13 @@ void GeoTagController::startTagging(void)
msgBox.setWindowModality(Qt::ApplicationModal); msgBox.setWindowModality(Qt::ApplicationModal);
msgBox.addButton(tr("Replace"), QMessageBox::ActionRole); msgBox.addButton(tr("Replace"), QMessageBox::ActionRole);
if (msgBox.exec() == QMessageBox::Cancel) { if (msgBox.exec() == QMessageBox::Cancel) {
_errorMessage = tr("Save folder not empty"); _setErrorMessage(tr("Save folder not empty"));
emit errorMessageChanged(_errorMessage);
return; return;
} }
foreach(QString dirFile, imageList) foreach(QString dirFile, imageList)
{ {
if(!saveDirectory.remove(dirFile)) { if(!saveDirectory.remove(dirFile)) {
_errorMessage = tr("Couldn't replace the existing images"); _setErrorMessage(tr("Couldn't replace the existing images"));
emit errorMessageChanged(_errorMessage);
return; return;
} }
} }
...@@ -144,6 +138,13 @@ void GeoTagController::_workerError(QString errorMessage) ...@@ -144,6 +138,13 @@ void GeoTagController::_workerError(QString errorMessage)
emit errorMessageChanged(errorMessage); emit errorMessageChanged(errorMessage);
} }
void GeoTagController::_setErrorMessage(const QString& error)
{
_errorMessage = error;
emit errorMessageChanged(error);
}
GeoTagWorker::GeoTagWorker(void) GeoTagWorker::GeoTagWorker(void)
: _cancel(false) : _cancel(false)
, _logFile("") , _logFile("")
...@@ -210,9 +211,10 @@ void GeoTagWorker::run(void) ...@@ -210,9 +211,10 @@ void GeoTagWorker::run(void)
// Instantiate appropriate parser // Instantiate appropriate parser
_triggerList.clear(); _triggerList.clear();
bool parseComplete = false; bool parseComplete = false;
if(isULog) { QString errorString;
if (isULog) {
ULogParser parser; ULogParser parser;
parseComplete = parser.getTagsFromLog(log, _triggerList); parseComplete = parser.getTagsFromLog(log, _triggerList, errorString);
} else { } else {
PX4LogParser parser; PX4LogParser parser;
...@@ -227,7 +229,8 @@ void GeoTagWorker::run(void) ...@@ -227,7 +229,8 @@ void GeoTagWorker::run(void)
return; return;
} else { } else {
qCDebug(GeotaggingLog) << "Log parsing failed"; qCDebug(GeotaggingLog) << "Log parsing failed";
emit error(tr("Log parsing failed - tagging cancelled")); errorString = tr("%1 - tagging cancelled").arg(errorString.isEmpty() ? tr("Log parsing failed") : errorString);
emit error(errorString);
return; return;
} }
} }
...@@ -259,6 +262,11 @@ void GeoTagWorker::run(void) ...@@ -259,6 +262,11 @@ void GeoTagWorker::run(void)
int maxIndex = std::min(_imageIndices.count(), _triggerIndices.count()); int maxIndex = std::min(_imageIndices.count(), _triggerIndices.count());
maxIndex = std::min(maxIndex, _imageList.count()); maxIndex = std::min(maxIndex, _imageList.count());
for(int i = 0; i < maxIndex; i++) { for(int i = 0; i < maxIndex; i++) {
int imageIndex = _imageIndices[i];
if (imageIndex >= _imageList.count()) {
emit error(tr("Geotagging failed. Image requested not present."));
return;
}
QFile fileRead(_imageList.at(_imageIndices[i]).absoluteFilePath()); QFile fileRead(_imageList.at(_imageIndices[i]).absoluteFilePath());
if (!fileRead.open(QIODevice::ReadOnly)) { if (!fileRead.open(QIODevice::ReadOnly)) {
emit error(tr("Geotagging failed. Couldn't open an image.")); emit error(tr("Geotagging failed. Couldn't open an image."));
......
...@@ -117,8 +117,9 @@ signals: ...@@ -117,8 +117,9 @@ signals:
void errorMessageChanged (QString errorMessage); void errorMessageChanged (QString errorMessage);
private slots: private slots:
void _workerProgressChanged(double progress); void _workerProgressChanged (double progress);
void _workerError(QString errorMsg); void _workerError (QString errorMsg);
void _setErrorMessage (const QString& error);
private: private:
QString _errorMessage; QString _errorMessage;
......
...@@ -124,8 +124,9 @@ AnalyzePage { ...@@ -124,8 +124,9 @@ AnalyzePage {
} }
QGCButton { QGCButton {
text: geoController.inProgress ? qsTr("Cancel Tagging") : qsTr("Start Tagging") text: geoController.inProgress ? qsTr("Cancel Tagging") : qsTr("Start Tagging")
width: ScreenTools.defaultFontPixelWidth * 30 width: ScreenTools.defaultFontPixelWidth * 30
onClicked: { onClicked: {
if (geoController.inProgress) { if (geoController.inProgress) {
geoController.cancelTagging() geoController.cancelTagging()
......
...@@ -321,7 +321,7 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui ...@@ -321,7 +321,7 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui
if(ofs <= _downloadData->entry->size()) { if(ofs <= _downloadData->entry->size()) {
const uint32_t chunk = ofs / kChunkSize; const uint32_t chunk = ofs / kChunkSize;
if (chunk != _downloadData->current_chunk) { if (chunk != _downloadData->current_chunk) {
qWarning() << "Ignored packet for out of order chunk" << chunk; qWarning() << "Ignored packet for out of order chunk actual:expected" << chunk << _downloadData->current_chunk;
return; return;
} }
const uint16_t bin = (ofs - chunk*kChunkSize) / MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN; const uint16_t bin = (ofs - chunk*kChunkSize) / MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN;
......
...@@ -51,8 +51,7 @@ AnalyzePage { ...@@ -51,8 +51,7 @@ AnalyzePage {
TableView { TableView {
id: tableView id: tableView
anchors.top: parent.top Layout.fillHeight: true
anchors.bottom: parent.bottom
model: logController.model model: logController.model
selectionMode: SelectionMode.MultiSelection selectionMode: SelectionMode.MultiSelection
Layout.fillWidth: true Layout.fillWidth: true
...@@ -155,7 +154,7 @@ AnalyzePage { ...@@ -155,7 +154,7 @@ AnalyzePage {
fileDialog.qgcView = logDownloadPage fileDialog.qgcView = logDownloadPage
fileDialog.title = qsTr("Select save directory") fileDialog.title = qsTr("Select save directory")
fileDialog.selectExisting = true fileDialog.selectExisting = true
fileDialog.folder = QGroundControl.settingsManager.appSettings.telemetrySavePath fileDialog.folder = QGroundControl.settingsManager.appSettings.logSavePath
fileDialog.selectFolder = true fileDialog.selectFolder = true
fileDialog.openForLoad() fileDialog.openForLoad()
} }
...@@ -186,7 +185,7 @@ AnalyzePage { ...@@ -186,7 +185,7 @@ AnalyzePage {
message: qsTr("All log files will be erased permanently. Is this really what you want?") message: qsTr("All log files will be erased permanently. Is this really what you want?")
function accept() { function accept() {
logDownloadPage.hideDialog() hideDialog()
logController.eraseAll() logController.eraseAll()
} }
} }
......
...@@ -33,12 +33,25 @@ MavlinkConsoleController::~MavlinkConsoleController() ...@@ -33,12 +33,25 @@ MavlinkConsoleController::~MavlinkConsoleController()
void void
MavlinkConsoleController::sendCommand(QString command) MavlinkConsoleController::sendCommand(QString command)
{ {
_history.append(command);
command.append("\n"); command.append("\n");
_sendSerialData(qPrintable(command)); _sendSerialData(qPrintable(command));
_cursor_home_pos = -1; _cursor_home_pos = -1;
_cursor = rowCount(); _cursor = rowCount();
} }
QString
MavlinkConsoleController::historyUp(const QString& current)
{
return _history.up(current);
}
QString
MavlinkConsoleController::historyDown(const QString& current)
{
return _history.down(current);
}
void void
MavlinkConsoleController::_setActiveVehicle(Vehicle* vehicle) MavlinkConsoleController::_setActiveVehicle(Vehicle* vehicle)
{ {
...@@ -192,3 +205,43 @@ MavlinkConsoleController::writeLine(int line, const QByteArray &text) ...@@ -192,3 +205,43 @@ MavlinkConsoleController::writeLine(int line, const QByteArray &text)
auto idx = index(line); auto idx = index(line);
setData(idx, data(idx, Qt::DisplayRole).toString() + text); setData(idx, data(idx, Qt::DisplayRole).toString() + text);
} }
void MavlinkConsoleController::CommandHistory::append(const QString& command)
{
if (command.length() > 0) {
// do not append duplicates
if (_history.length() == 0 || _history.last() != command) {
if (_history.length() >= maxHistoryLength) {
_history.removeFirst();
}
_history.append(command);
}
}
_index = _history.length();
}
QString MavlinkConsoleController::CommandHistory::up(const QString& current)
{
if (_index <= 0)
return current;
--_index;
if (_index < _history.length()) {
return _history[_index];
}
return "";
}
QString MavlinkConsoleController::CommandHistory::down(const QString& current)
{
if (_index >= _history.length())
return current;
++_index;
if (_index < _history.length()) {
return _history[_index];
}
return "";
}
...@@ -27,13 +27,12 @@ class MavlinkConsoleController : public QStringListModel ...@@ -27,13 +27,12 @@ class MavlinkConsoleController : public QStringListModel
public: public:
MavlinkConsoleController(); MavlinkConsoleController();
~MavlinkConsoleController(); virtual ~MavlinkConsoleController();
public slots: Q_INVOKABLE void sendCommand(QString command);
void sendCommand(QString command);
signals: Q_INVOKABLE QString historyUp(const QString& current);
void cursorChanged(int); Q_INVOKABLE QString historyDown(const QString& current);
private slots: private slots:
void _setActiveVehicle (Vehicle* vehicle); void _setActiveVehicle (Vehicle* vehicle);
...@@ -44,10 +43,23 @@ private: ...@@ -44,10 +43,23 @@ private:
void _sendSerialData(QByteArray, bool close = false); void _sendSerialData(QByteArray, bool close = false);
void writeLine(int line, const QByteArray &text); void writeLine(int line, const QByteArray &text);
class CommandHistory
{
public:
void append(const QString& command);
QString up(const QString& current);
QString down(const QString& current);
private:
static constexpr int maxHistoryLength = 100;
QList<QString> _history;
int _index = 0;
};
int _cursor_home_pos; int _cursor_home_pos;
int _cursor; int _cursor;
QByteArray _incoming_buffer; QByteArray _incoming_buffer;
Vehicle* _vehicle; Vehicle* _vehicle;
QList<QMetaObject::Connection> _uas_connections; QList<QMetaObject::Connection> _uas_connections;
CommandHistory _history;
}; };
...@@ -26,7 +26,7 @@ AnalyzePage { ...@@ -26,7 +26,7 @@ AnalyzePage {
pageName: qsTr("Mavlink Console") pageName: qsTr("Mavlink Console")
pageDescription: qsTr("Mavlink Console provides a connection to the vehicle's system shell.") pageDescription: qsTr("Mavlink Console provides a connection to the vehicle's system shell.")
property bool loaded: false property bool isLoaded: false
Component { Component {
id: pageComponent id: pageComponent
...@@ -41,7 +41,7 @@ AnalyzePage { ...@@ -41,7 +41,7 @@ AnalyzePage {
onDataChanged: { onDataChanged: {
// Keep the view in sync if the button is checked // Keep the view in sync if the button is checked
if (loaded) { if (isLoaded) {
if (followTail.checked) { if (followTail.checked) {
listview.positionViewAtEnd(); listview.positionViewAtEnd();
} }
...@@ -53,7 +53,7 @@ AnalyzePage { ...@@ -53,7 +53,7 @@ AnalyzePage {
id: delegateItem id: delegateItem
Rectangle { Rectangle {
color: qgcPal.windowShade color: qgcPal.windowShade
height: Math.round(ScreenTools.defaultFontPixelHeight * 0.5 + field.height) height: Math.round(ScreenTools.defaultFontPixelHeight * 0.1 + field.height)
width: listview.width width: listview.width
QGCLabel { QGCLabel {
...@@ -69,11 +69,10 @@ AnalyzePage { ...@@ -69,11 +69,10 @@ AnalyzePage {
QGCListView { QGCListView {
Component.onCompleted: { Component.onCompleted: {
loaded = true isLoaded = true
} }
Layout.fillHeight: true Layout.fillHeight: true
anchors.left: parent.left Layout.fillWidth: true
anchors.right: parent.right
clip: true clip: true
id: listview id: listview
model: conController model: conController
...@@ -86,8 +85,7 @@ AnalyzePage { ...@@ -86,8 +85,7 @@ AnalyzePage {
} }
RowLayout { RowLayout {
anchors.left: parent.left Layout.fillWidth: true
anchors.right: parent.right
QGCTextField { QGCTextField {
id: command id: command
Layout.fillWidth: true Layout.fillWidth: true
...@@ -96,6 +94,15 @@ AnalyzePage { ...@@ -96,6 +94,15 @@ AnalyzePage {
conController.sendCommand(text) conController.sendCommand(text)
text = "" text = ""
} }
Keys.onPressed: {
if (event.key == Qt.Key_Up) {
text = conController.historyUp(text);
event.accepted = true;
} else if (event.key == Qt.Key_Down) {
text = conController.historyDown(text);
event.accepted = true;
}
}
} }
QGCButton { QGCButton {
...@@ -105,7 +112,7 @@ AnalyzePage { ...@@ -105,7 +112,7 @@ AnalyzePage {
checked: true checked: true
onCheckedChanged: { onCheckedChanged: {
if (checked && loaded) { if (checked && isLoaded) {
listview.positionViewAtEnd(); listview.positionViewAtEnd();
} }
} }
......
...@@ -86,11 +86,13 @@ bool ULogParser::parseFieldFormat(QString& fields) ...@@ -86,11 +86,13 @@ bool ULogParser::parseFieldFormat(QString& fields)
return false; return false;
} }
bool ULogParser::getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedbackPacket>& cameraFeedback) bool ULogParser::getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedbackPacket>& cameraFeedback, QString& errorMessage)
{ {
errorMessage.clear();
//verify it's an ULog file //verify it's an ULog file
if(!log.contains(_ULogMagic)) { if(!log.contains(_ULogMagic)) {
qWarning() << "Could not detect ULog file header magic"; errorMessage = tr("Could not detect ULog file header magic");
return false; return false;
} }
...@@ -139,15 +141,10 @@ bool ULogParser::getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedb ...@@ -139,15 +141,10 @@ bool ULogParser::getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedb
case (int)ULogMessageType::DATA: case (int)ULogMessageType::DATA:
{ {
if (!geotagFound) {
qWarning() << "Could not detect geotag packets in ULog";
return false;
}
uint16_t msgID = -1; uint16_t msgID = -1;
memcpy(&msgID, log.data() + index + ULOG_MSG_HEADER_LEN, 2); memcpy(&msgID, log.data() + index + ULOG_MSG_HEADER_LEN, 2);
if(msgID == _cameraCaptureMsgID) { if (geotagFound && msgID == _cameraCaptureMsgID) {
// Completely dynamic parsing, so that changing/reordering the message format will not break the parser // Completely dynamic parsing, so that changing/reordering the message format will not break the parser
GeoTagWorker::cameraFeedbackPacket feedback; GeoTagWorker::cameraFeedbackPacket feedback;
...@@ -179,5 +176,10 @@ bool ULogParser::getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedb ...@@ -179,5 +176,10 @@ bool ULogParser::getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedb
} }
if (cameraFeedback.count() == 0) {
errorMessage = tr("Could not detect camera_capture packets in ULog");
return false;
}
return true; return true;
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <QGeoCoordinate> #include <QGeoCoordinate>
#include <QDebug> #include <QDebug>
#include <QCoreApplication>
#include "GeoTagController.h" #include "GeoTagController.h"
...@@ -10,10 +11,14 @@ ...@@ -10,10 +11,14 @@
class ULogParser class ULogParser
{ {
Q_DECLARE_TR_FUNCTIONS(ULogParser)
public: public:
ULogParser(); ULogParser();
~ULogParser(); ~ULogParser();
bool getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedbackPacket>& cameraFeedback);
/// @return true: failed, errorMessage set
bool getTagsFromLog(QByteArray& log, QList<GeoTagWorker::cameraFeedbackPacket>& cameraFeedback, QString& errorMessage);
private: private:
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
AudioOutput::AudioOutput(QGCApplication* app, QGCToolbox* toolbox) AudioOutput::AudioOutput(QGCApplication* app, QGCToolbox* toolbox)
: QGCTool(app, toolbox) : QGCTool(app, toolbox)
, _tts(new QTextToSpeech(this))
{ {
_tts = new QTextToSpeech(this);
connect(_tts, &QTextToSpeech::stateChanged, this, &AudioOutput::_stateChanged); connect(_tts, &QTextToSpeech::stateChanged, this, &AudioOutput::_stateChanged);
} }
...@@ -73,6 +73,7 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) { ...@@ -73,6 +73,7 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) {
QString match; QString match;
QString newNumber; QString newNumber;
QString result = string; QString result = string;
//-- Look for codified terms //-- Look for codified terms
if(result.contains("ERR ", Qt::CaseInsensitive)) { if(result.contains("ERR ", Qt::CaseInsensitive)) {
result.replace("ERR ", "error ", Qt::CaseInsensitive); result.replace("ERR ", "error ", Qt::CaseInsensitive);
...@@ -118,6 +119,9 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) { ...@@ -118,6 +119,9 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) {
if(result.contains(" ADSB ", Qt::CaseInsensitive)) { if(result.contains(" ADSB ", Qt::CaseInsensitive)) {
result.replace(" ADSB ", " Hey Dee Ess Bee ", Qt::CaseInsensitive); result.replace(" ADSB ", " Hey Dee Ess Bee ", Qt::CaseInsensitive);
} }
if(result.contains(" EKF ", Qt::CaseInsensitive)) {
result.replace(" EKF ", " Eee Kay Eff ", Qt::CaseInsensitive);
}
// Convert negative numbers // Convert negative numbers
QRegularExpression re(QStringLiteral("(-)[0-9]*\\.?[0-9]")); QRegularExpression re(QStringLiteral("(-)[0-9]*\\.?[0-9]"));
...@@ -125,9 +129,18 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) { ...@@ -125,9 +129,18 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) {
while (reMatch.hasMatch()) { while (reMatch.hasMatch()) {
if (!reMatch.captured(1).isNull()) { if (!reMatch.captured(1).isNull()) {
// There is a negative prefix // There is a negative prefix
qDebug() << "negative" << reMatch.captured(1) << reMatch.capturedStart(1) << reMatch.capturedEnd(1);
result.replace(reMatch.capturedStart(1), reMatch.capturedEnd(1) - reMatch.capturedStart(1), tr(" negative ")); result.replace(reMatch.capturedStart(1), reMatch.capturedEnd(1) - reMatch.capturedStart(1), tr(" negative "));
qDebug() << result; }
reMatch = re.match(result);
}
// Convert real number with decimal point
re.setPattern(QStringLiteral("([0-9]+)(\\.)([0-9]+)"));
reMatch = re.match(result);
while (reMatch.hasMatch()) {
if (!reMatch.captured(2).isNull()) {
// There is a decimal point
result.replace(reMatch.capturedStart(2), reMatch.capturedEnd(2) - reMatch.capturedStart(2), tr(" point "));
} }
reMatch = re.match(result); reMatch = re.match(result);
} }
...@@ -138,9 +151,7 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) { ...@@ -138,9 +151,7 @@ QString AudioOutput::fixTextMessageForAudio(const QString& string) {
while (reMatch.hasMatch()) { while (reMatch.hasMatch()) {
if (!reMatch.captured(1).isNull()) { if (!reMatch.captured(1).isNull()) {
// There is a meter postfix // There is a meter postfix
qDebug() << "meters" << reMatch.captured(1) << reMatch.capturedStart(1) << reMatch.capturedEnd(1);
result.replace(reMatch.capturedStart(1), reMatch.capturedEnd(1) - reMatch.capturedStart(1), tr(" meters")); result.replace(reMatch.capturedStart(1), reMatch.capturedEnd(1) - reMatch.capturedStart(1), tr(" meters"));
qDebug() << result;
} }
reMatch = re.match(result); reMatch = re.match(result);
} }
......
...@@ -18,7 +18,7 @@ AudioOutputTest::AudioOutputTest(void) ...@@ -18,7 +18,7 @@ AudioOutputTest::AudioOutputTest(void)
void AudioOutputTest::_testSpokenReplacements(void) void AudioOutputTest::_testSpokenReplacements(void)
{ {
QString result = AudioOutput::fixTextMessageForAudio(QStringLiteral("-10.5m, -10.5m. -10.5 m")); QString result = AudioOutput::fixTextMessageForAudio(QStringLiteral("-10.5m, -10.5m. -10.5 m"));
QCOMPARE(result, QStringLiteral(" negative 10.5 meters, negative 10.5 meters. negative 10.5 meters")); QCOMPARE(result, QStringLiteral(" negative 10 point 5 meters, negative 10 point 5 meters. negative 10 point 5 meters"));
result = AudioOutput::fixTextMessageForAudio(QStringLiteral("-10m -10 m")); result = AudioOutput::fixTextMessageForAudio(QStringLiteral("-10m -10 m"));
QCOMPARE(result, QStringLiteral(" negative 10 meters negative 10 meters")); QCOMPARE(result, QStringLiteral(" negative 10 meters negative 10 meters"));
result = AudioOutput::fixTextMessageForAudio(QStringLiteral("foo -10m -10 m bar")); result = AudioOutput::fixTextMessageForAudio(QStringLiteral("foo -10m -10 m bar"));
......
...@@ -83,10 +83,9 @@ SetupPage { ...@@ -83,10 +83,9 @@ SetupPage {
id: newFramePageComponent id: newFramePageComponent
Grid { Grid {
anchors.left: parent.left width: availableWidth
anchors.right: parent.right spacing: _margins
spacing: _margins columns: 2
columns: 2
QGCLabel { QGCLabel {
text: qsTr("Frame Class:") text: qsTr("Frame Class:")
......
...@@ -18,36 +18,36 @@ FactPanel { ...@@ -18,36 +18,36 @@ FactPanel {
factPanel: panel factPanel: panel
} }
property bool _useOldFrameParam: controller.parameterExists(-1, "FRAME") property bool _frameAvailable: controller.parameterExists(-1, "FRAME")
property Fact _oldFrameParam: controller.getParameterFact(-1, "FRAME", false)
property Fact _newFrameParam: controller.getParameterFact(-1, "FRAME_CLASS", false) property Fact _frame: controller.getParameterFact(-1, "FRAME", false)
property Fact _frameTypeParam: controller.getParameterFact(-1, "FRAME_TYPE", false) property Fact _frameClass: controller.getParameterFact(-1, "FRAME_CLASS", false)
property Fact _frameType: controller.getParameterFact(-1, "FRAME_TYPE", false)
Column { Column {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Frame Type:") labelText: qsTr("Frame Type")
valueText: controller.currentAirframeTypeName() + " " + _oldFrameParam.enumStringValue valueText: visible ? controller.currentAirframeTypeName() + " " + _frame.enumStringValue : ""
visible: _useOldFrameParam visible: _frameAvailable
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Frame Class:") labelText: qsTr("Frame Class")
valueText: _newFrameParam.enumStringValue valueText: visible ? _frameClass.enumStringValue : ""
visible: !_useOldFrameParam visible: !_frameAvailable
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Frame Type:") labelText: qsTr("Frame Type")
valueText: _frameTypeParam.enumStringValue valueText: visible ? _frameType.enumStringValue : ""
visible: !_useOldFrameParam visible: !_frameAvailable
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Firmware Version:") labelText: qsTr("Firmware Version")
valueText: activeVehicle.firmwareMajorVersion == -1 ? qsTr("Unknown") : activeVehicle.firmwareMajorVersion + "." + activeVehicle.firmwareMinorVersion + "." + activeVehicle.firmwarePatchVersion + activeVehicle.firmwareVersionTypeString valueText: activeVehicle.firmwareMajorVersion == -1 ? qsTr("Unknown") : activeVehicle.firmwareMajorVersion + "." + activeVehicle.firmwareMinorVersion + "." + activeVehicle.firmwarePatchVersion + activeVehicle.firmwareVersionTypeString
} }
} }
......
...@@ -28,27 +28,29 @@ ...@@ -28,27 +28,29 @@
#include "APMLightsComponent.h" #include "APMLightsComponent.h"
#include "APMSubFrameComponent.h" #include "APMSubFrameComponent.h"
#include "ESP8266Component.h" #include "ESP8266Component.h"
#include "APMHeliComponent.h"
/// This is the AutoPilotPlugin implementatin for the MAV_AUTOPILOT_ARDUPILOT type. /// This is the AutoPilotPlugin implementatin for the MAV_AUTOPILOT_ARDUPILOT type.
APMAutoPilotPlugin::APMAutoPilotPlugin(Vehicle* vehicle, QObject* parent) APMAutoPilotPlugin::APMAutoPilotPlugin(Vehicle* vehicle, QObject* parent)
: AutoPilotPlugin(vehicle, parent) : AutoPilotPlugin (vehicle, parent)
, _incorrectParameterVersion(false) , _incorrectParameterVersion(false)
, _airframeComponent(NULL) , _airframeComponent (NULL)
, _cameraComponent(NULL) , _cameraComponent (NULL)
, _lightsComponent(NULL) , _lightsComponent (NULL)
, _subFrameComponent(NULL) , _subFrameComponent (NULL)
, _flightModesComponent(NULL) , _flightModesComponent (NULL)
, _powerComponent(NULL) , _powerComponent (NULL)
#if 0 #if 0
// Temporarily removed, waiting for new command implementation // Temporarily removed, waiting for new command implementation
, _motorComponent(NULL) , _motorComponent (NULL)
#endif #endif
, _radioComponent(NULL) , _radioComponent (NULL)
, _safetyComponent(NULL) , _safetyComponent (NULL)
, _sensorsComponent(NULL) , _sensorsComponent (NULL)
, _tuningComponent(NULL) , _tuningComponent (NULL)
, _airframeFacts(new APMAirframeLoader(this, vehicle->uas(), this)) , _airframeFacts (new APMAirframeLoader(this, vehicle->uas(), this))
, _esp8266Component(NULL) , _esp8266Component (NULL)
, _heliComponent (NULL)
{ {
APMAirframeLoader::loadAirframeFactMetaData(); APMAirframeLoader::loadAirframeFactMetaData();
} }
...@@ -101,6 +103,12 @@ const QVariantList& APMAutoPilotPlugin::vehicleComponents(void) ...@@ -101,6 +103,12 @@ const QVariantList& APMAutoPilotPlugin::vehicleComponents(void)
_safetyComponent->setupTriggerSignals(); _safetyComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_safetyComponent)); _components.append(QVariant::fromValue((VehicleComponent*)_safetyComponent));
if (_vehicle->vehicleType() == MAV_TYPE_HELICOPTER) {
_heliComponent = new APMHeliComponent(_vehicle, this);
_heliComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_heliComponent));
}
_tuningComponent = new APMTuningComponent(_vehicle, this); _tuningComponent = new APMTuningComponent(_vehicle, this);
_tuningComponent->setupTriggerSignals(); _tuningComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_tuningComponent)); _components.append(QVariant::fromValue((VehicleComponent*)_tuningComponent));
......
...@@ -27,6 +27,7 @@ class APMCameraComponent; ...@@ -27,6 +27,7 @@ class APMCameraComponent;
class APMLightsComponent; class APMLightsComponent;
class APMSubFrameComponent; class APMSubFrameComponent;
class ESP8266Component; class ESP8266Component;
class APMHeliComponent;
/// This is the APM specific implementation of the AutoPilot class. /// This is the APM specific implementation of the AutoPilot class.
class APMAutoPilotPlugin : public AutoPilotPlugin class APMAutoPilotPlugin : public AutoPilotPlugin
...@@ -59,6 +60,7 @@ protected: ...@@ -59,6 +60,7 @@ protected:
APMTuningComponent* _tuningComponent; APMTuningComponent* _tuningComponent;
APMAirframeLoader* _airframeFacts; APMAirframeLoader* _airframeFacts;
ESP8266Component* _esp8266Component; ESP8266Component* _esp8266Component;
APMHeliComponent* _heliComponent;
private: private:
QVariantList _components; QVariantList _components;
......
...@@ -170,17 +170,29 @@ SetupPage { ...@@ -170,17 +170,29 @@ SetupPage {
ListModel { ListModel {
id: gimbalOutModel id: gimbalOutModel
// It appears that QGCComboBox can't handle models that don't have a initial item
// after onModelChanged
ListElement { text: qsTr("Disabled"); value: 0 } ListElement { text: qsTr("Disabled"); value: 0 }
ListElement { text: qsTr("Channel 5"); value: 5 }
ListElement { text: qsTr("Channel 6"); value: 6 } function update(number) {
ListElement { text: qsTr("Channel 7"); value: 7 } // Not enough channels
ListElement { text: qsTr("Channel 8"); value: 8 } if(number < 6) {
ListElement { text: qsTr("Channel 9"); value: 9 } return
ListElement { text: qsTr("Channel 10"); value: 10 } }
ListElement { text: qsTr("Channel 11"); value: 11 } for(var i = 5; i <= number; i++) {
ListElement { text: qsTr("Channel 12"); value: 12 } var text = qsTr("Channel ") + i
ListElement { text: qsTr("Channel 13"); value: 13 } append({"text": text, "value": i})
ListElement { text: qsTr("Channel 14"); value: 14 } }
}
Component.onCompleted: {
// Number of main outputs
var baseValue = 8
// Extra outputs
// http://ardupilot.org/copter/docs/parameters.html#brd-pwm-count-auxiliary-pin-config
var brd_pwm_count_value = controller.getParameterFact(-1, "BRD_PWM_COUNT").value
update(8 + (brd_pwm_count_value == 7 ? 3 : brd_pwm_count_value))
}
} }
Component { Component {
......
...@@ -27,22 +27,22 @@ FactPanel { ...@@ -27,22 +27,22 @@ FactPanel {
VehicleSummaryRow { VehicleSummaryRow {
visible: _mountTypeExists visible: _mountTypeExists
labelText: qsTr("Gimbal type:") labelText: qsTr("Gimbal type")
valueText: _mountTypeValue valueText: _mountTypeValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Tilt input channel:") labelText: qsTr("Tilt input channel")
valueText: _mountRCInTilt.enumStringValue valueText: _mountRCInTilt.enumStringValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Pan input channel:") labelText: qsTr("Pan input channel")
valueText: _mountRCInPan.enumStringValue valueText: _mountRCInPan.enumStringValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Roll input channel:") labelText: qsTr("Roll input channel")
valueText: _mountRCInRoll.enumStringValue valueText: _mountRCInRoll.enumStringValue
} }
} }
......
...@@ -68,7 +68,7 @@ void APMFlightModesComponentController::_rcChannelsChanged(int channelCount, int ...@@ -68,7 +68,7 @@ void APMFlightModesComponentController::_rcChannelsChanged(int channelCount, int
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
_rgChannelOptionEnabled[i] = QVariant(false); _rgChannelOptionEnabled[i] = QVariant(false);
channelValue = pwmValues[i+6]; channelValue = pwmValues[i+6];
if (channelValue != -1 && channelValue > 1800) { if (channelValue > 1800) {
_rgChannelOptionEnabled[i] = QVariant(true); _rgChannelOptionEnabled[i] = QVariant(true);
} }
} }
......
...@@ -27,32 +27,32 @@ FactPanel { ...@@ -27,32 +27,32 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flight Mode 1:") labelText: qsTr("Flight Mode 1")
valueText: flightMode1.enumStringValue valueText: flightMode1.enumStringValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flight Mode 2:") labelText: qsTr("Flight Mode 2")
valueText: flightMode2.enumStringValue valueText: flightMode2.enumStringValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flight Mode 3:") labelText: qsTr("Flight Mode 3")
valueText: flightMode3.enumStringValue valueText: flightMode3.enumStringValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flight Mode 4:") labelText: qsTr("Flight Mode 4")
valueText: flightMode4.enumStringValue valueText: flightMode4.enumStringValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flight Mode 5:") labelText: qsTr("Flight Mode 5")
valueText: flightMode5.enumStringValue valueText: flightMode5.enumStringValue
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flight Mode 6:") labelText: qsTr("Flight Mode 6")
valueText: flightMode6.enumStringValue valueText: flightMode6.enumStringValue
} }
} }
......
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "APMHeliComponent.h"
#include "APMAutoPilotPlugin.h"
APMHeliComponent::APMHeliComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent)
: VehicleComponent(vehicle, autopilot, parent)
, _name(tr("Heli"))
{
}
QString APMHeliComponent::name(void) const
{
return _name;
}
QString APMHeliComponent::description(void) const
{
return tr("Heli Setup is used to setup parameters which are specific to a helicopter.");
}
QString APMHeliComponent::iconResource(void) const
{
return QString();
}
bool APMHeliComponent::requiresSetup(void) const
{
return false;
}
bool APMHeliComponent::setupComplete(void) const
{
return true;
}
QStringList APMHeliComponent::setupCompleteChangedTriggerList(void) const
{
return QStringList();
}
QUrl APMHeliComponent::setupSource(void) const
{
return QStringLiteral("qrc:/qml/APMHeliComponent.qml");
}
QUrl APMHeliComponent::summaryQmlSource(void) const
{
return QUrl();
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include "VehicleComponent.h"
class APMHeliComponent : public VehicleComponent
{
Q_OBJECT
public:
APMHeliComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL);
// Virtuals from VehicleComponent
QStringList setupCompleteChangedTriggerList(void) const override;
// Virtuals from VehicleComponent
QString name(void) const override;
QString description(void) const override;
QString iconResource(void) const override;
bool requiresSetup(void) const override;
bool setupComplete(void) const override;
QUrl setupSource(void) const override;
QUrl summaryQmlSource(void) const override;
bool allowSetupWhileArmed(void) const override { return true; }
private:
const QString _name;
QVariantList _summaryItems;
};
This diff is collapsed.
...@@ -132,17 +132,29 @@ SetupPage { ...@@ -132,17 +132,29 @@ SetupPage {
ListModel { ListModel {
id: lightsOutModel id: lightsOutModel
// It appears that QGCComboBox can't handle models that don't have a initial item
// after onModelChanged
ListElement { text: qsTr("Disabled"); value: 0 } ListElement { text: qsTr("Disabled"); value: 0 }
ListElement { text: qsTr("Channel 5"); value: 5 }
ListElement { text: qsTr("Channel 6"); value: 6 } function update(number) {
ListElement { text: qsTr("Channel 7"); value: 7 } // Not enough channels
ListElement { text: qsTr("Channel 8"); value: 8 } if(number < 6) {
ListElement { text: qsTr("Channel 9"); value: 9 } return
ListElement { text: qsTr("Channel 10"); value: 10 } }
ListElement { text: qsTr("Channel 11"); value: 11 } for(var i = 5; i <= number; i++) {
ListElement { text: qsTr("Channel 12"); value: 12 } var text = qsTr("Channel ") + i
ListElement { text: qsTr("Channel 13"); value: 13 } append({"text": text, "value": i})
ListElement { text: qsTr("Channel 14"); value: 14 } }
}
Component.onCompleted: {
// Number of main outputs
var baseValue = 8
// Extra outputs
// http://ardupilot.org/copter/docs/parameters.html#brd-pwm-count-auxiliary-pin-config
var brd_pwm_count_value = controller.getParameterFact(-1, "BRD_PWM_COUNT").value
update(8 + (brd_pwm_count_value == 7 ? 3 : brd_pwm_count_value))
}
} }
Component { Component {
......
...@@ -89,12 +89,12 @@ FactPanel { ...@@ -89,12 +89,12 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Lights Output 1:") labelText: qsTr("Lights Output 1")
valueText: lightsOutModel.get(lightsLoader.lights1OutIndex).text valueText: lightsOutModel.get(lightsLoader.lights1OutIndex).text
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Lights Output 2:") labelText: qsTr("Lights Output 2")
valueText: lightsOutModel.get(lightsLoader.lights2OutIndex).text valueText: lightsOutModel.get(lightsLoader.lights2OutIndex).text
} }
} }
......
...@@ -20,18 +20,19 @@ class APMPowerComponent : public VehicleComponent ...@@ -20,18 +20,19 @@ class APMPowerComponent : public VehicleComponent
public: public:
APMPowerComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL); APMPowerComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL);
// Virtuals from VehicleComponent // Overrides from VehicleComponent
QStringList setupCompleteChangedTriggerList(void) const final; QStringList setupCompleteChangedTriggerList(void) const override;
// Virtuals from VehicleComponent // Virtuals from VehicleComponent
QString name (void) const final; QString name (void) const override;
QString description (void) const final; QString description (void) const override;
QString iconResource (void) const final; QString iconResource (void) const override;
bool requiresSetup (void) const final; bool requiresSetup (void) const override;
bool setupComplete (void) const final; bool setupComplete (void) const override;
QUrl setupSource (void) const final; QUrl setupSource (void) const override;
QUrl summaryQmlSource (void) const final; QUrl summaryQmlSource (void) const override;
bool allowSetupWhileArmed (void) const override { return true; }
private: private:
const QString _name; const QString _name;
QVariantList _summaryItems; QVariantList _summaryItems;
......
...@@ -24,20 +24,37 @@ FactPanel { ...@@ -24,20 +24,37 @@ FactPanel {
QGCPalette { id: qgcPal; colorGroupEnabled: enabled } QGCPalette { id: qgcPal; colorGroupEnabled: enabled }
FactPanelController { id: controller; factPanel: panel } FactPanelController { id: controller; factPanel: panel }
property Fact battCapacity: controller.getParameterFact(-1, "BATT_CAPACITY") property bool _batt2MonitorAvailable: controller.parameterExists(-1, "BATT2_MONITOR")
property Fact battMonitor: controller.getParameterFact(-1, "BATT_MONITOR") property bool _batt2CapacityAvailable: controller.parameterExists(-1, "BATT2_CAPACITY")
property Fact _battCapacity: controller.getParameterFact(-1, "BATT_CAPACITY")
property Fact _batt2Capacity: controller.getParameterFact(-1, "BATT2_CAPACITY", false /* reportMissing */)
property Fact _battMonitor: controller.getParameterFact(-1, "BATT_MONITOR")
property Fact _batt2Monitor: controller.getParameterFact(-1, "BATT2_MONITOR", false /* reportMissing */)
Column { Column {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Battery monitor:") labelText: qsTr("Battery monitor")
valueText: battMonitor.enumStringValue valueText: _battMonitor.enumStringValue
}
VehicleSummaryRow {
labelText: qsTr("Battery capacity")
valueText: _battCapacity.valueString + " " + _battCapacity.units
}
VehicleSummaryRow {
labelText: qsTr("Battery2 monitor")
valueText: _batt2MonitorAvailable ? _batt2Monitor.enumStringValue : ""
visible: _batt2MonitorAvailable
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Battery capacity:") labelText: qsTr("Battery2 capacity")
valueText: battCapacity.valueString + " " + battCapacity.units valueText: _batt2CapacityAvailable ? _batt2Capacity.valueString + " " + _battCapacity.units : ""
visible: _batt2CapacityAvailable
} }
} }
} }
...@@ -23,22 +23,22 @@ FactPanel { ...@@ -23,22 +23,22 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Roll:") labelText: qsTr("Roll")
valueText: mapRollFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapRollFact.valueString) valueText: mapRollFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapRollFact.valueString)
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Pitch:") labelText: qsTr("Pitch")
valueText: mapPitchFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapPitchFact.valueString) valueText: mapPitchFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapPitchFact.valueString)
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Yaw:") labelText: qsTr("Yaw")
valueText: mapYawFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapYawFact.valueString) valueText: mapYawFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapYawFact.valueString)
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Throttle:") labelText: qsTr("Throttle")
valueText: mapThrottleFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapThrottleFact.valueString) valueText: mapThrottleFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapThrottleFact.valueString)
} }
} }
......
...@@ -34,8 +34,8 @@ SetupPage { ...@@ -34,8 +34,8 @@ SetupPage {
QGCPalette { id: palette; colorGroupEnabled: true } QGCPalette { id: palette; colorGroupEnabled: true }
property Fact _failsafeBattMah: controller.getParameterFact(-1, "FS_BATT_MAH") property Fact _failsafeBattMah: controller.getParameterFact(-1, "r.BATT_LOW_MAH")
property Fact _failsafeBattVoltage: controller.getParameterFact(-1, "FS_BATT_VOLTAGE") property Fact _failsafeBattVoltage: controller.getParameterFact(-1, "r.BATT_LOW_VOLT")
property Fact _failsafeThrEnable: controller.getParameterFact(-1, "THR_FAILSAFE") property Fact _failsafeThrEnable: controller.getParameterFact(-1, "THR_FAILSAFE")
property Fact _failsafeThrValue: controller.getParameterFact(-1, "THR_FS_VALUE") property Fact _failsafeThrValue: controller.getParameterFact(-1, "THR_FS_VALUE")
property Fact _failsafeGCSEnable: controller.getParameterFact(-1, "FS_GCS_ENABL") property Fact _failsafeGCSEnable: controller.getParameterFact(-1, "FS_GCS_ENABL")
......
...@@ -14,7 +14,7 @@ FactPanel { ...@@ -14,7 +14,7 @@ FactPanel {
QGCPalette { id: qgcPal; colorGroupEnabled: enabled } QGCPalette { id: qgcPal; colorGroupEnabled: enabled }
FactPanelController { id: controller; factPanel: panel } FactPanelController { id: controller; factPanel: panel }
property Fact _failsafeBattEnable: controller.getParameterFact(-1, "FS_BATT_ENABLE") property Fact _failsafeBattLowAct: controller.getParameterFact(-1, "r.BATT_FS_LOW_ACT")
property Fact _failsafeThrEnable: controller.getParameterFact(-1, "FS_THR_ENABLE") property Fact _failsafeThrEnable: controller.getParameterFact(-1, "FS_THR_ENABLE")
property Fact _fenceAction: controller.getParameterFact(-1, "FENCE_ACTION") property Fact _fenceAction: controller.getParameterFact(-1, "FENCE_ACTION")
...@@ -28,60 +28,14 @@ FactPanel { ...@@ -28,60 +28,14 @@ FactPanel {
property Fact _armingCheck: controller.getParameterFact(-1, "ARMING_CHECK") property Fact _armingCheck: controller.getParameterFact(-1, "ARMING_CHECK")
property string _failsafeBattEnableText property bool _failsafeBattCritActAvailable: controller.parameterExists(-1, "BATT_FS_CRT_ACT")
property string _failsafeThrEnableText property bool _failsafeBatt2LowActAvailable: controller.parameterExists(-1, "BATT2_FS_LOW_ACT")
property bool _failsafeBatt2CritActAvailable: controller.parameterExists(-1, "BATT2_FS_CRT_ACT")
Component.onCompleted: { property Fact _failsafeBattCritAct: controller.getParameterFact(-1, "BATT_FS_CRT_ACT", false /* reportMissing */)
setFailsafeBattEnableText() property Fact _batt2Monitor: controller.getParameterFact(-1, "BATT2_MONITOR", false /* reportMissing */)
setFailsafeThrEnableText() property Fact _failsafeBatt2LowAct: controller.getParameterFact(-1, "BATT2_FS_LOW_ACT", false /* reportMissing */)
} property Fact _failsafeBatt2CritAct: controller.getParameterFact(-1, "BATT2_FS_CRT_ACT", false /* reportMissing */)
Connections {
target: _failsafeBattEnable
onValueChanged: setFailsafeBattEnableText()
}
Connections {
target: _failsafeThrEnable
onValueChanged: setFailsafeThrEnableText()
}
function setFailsafeThrEnableText() {
switch (_failsafeThrEnable.value) {
case 0:
_failsafeThrEnableText = qsTr("Disabled")
break
case 1:
_failsafeThrEnableText = qsTr("Always RTL")
break
case 2:
_failsafeThrEnableText = qsTr("Continue with Mission in Auto Mode")
break
case 3:
_failsafeThrEnableText = qsTr("Always Land")
break
default:
_failsafeThrEnableText = qsTr("Unknown")
}
}
function setFailsafeBattEnableText() {
switch (_failsafeBattEnable.value) {
case 0:
_failsafeBattEnableText = qsTr("Disabled")
break
case 1:
_failsafeBattEnableText = qsTr("Land")
break
case 2:
_failsafeBattEnableText = qsTr("Return to Launch")
break
default:
_failsafeThrEnableText = qsTr("Unknown")
}
}
Column { Column {
anchors.fill: parent anchors.fill: parent
...@@ -93,12 +47,30 @@ FactPanel { ...@@ -93,12 +47,30 @@ FactPanel {
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Throttle failsafe:") labelText: qsTr("Throttle failsafe:")
valueText: _failsafeThrEnableText valueText: _failsafeBattLowAct.enumStringValue
}
VehicleSummaryRow {
labelText: qsTr("Batt low failsafe:")
valueText: _failsafeBattLowAct.enumStringValue
}
VehicleSummaryRow {
labelText: qsTr("Batt critical failsafe:")
valueText: _failsafeBattCritActAvailable ? _failsafeBattCritAct.enumStringValue : ""
visible: _failsafeBattCritActAvailable
}
VehicleSummaryRow {
labelText: qsTr("Batt2 low failsafe:")
valueText: _failsafeBatt2LowActAvailable ? _failsafeBatt2LowAct.enumStringValue : ""
visible: _failsafeBatt2LowActAvailable
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Battery failsafe:") labelText: qsTr("Batt2 critical failsafe:")
valueText: _failsafeBattEnableText valueText: _failsafeBatt2CritActAvailable ? _failsafeBatt2CritAct.enumStringValue : ""
visible: _failsafeBatt2CritActAvailable
} }
VehicleSummaryRow { VehicleSummaryRow {
......
...@@ -34,7 +34,7 @@ FactPanel { ...@@ -34,7 +34,7 @@ FactPanel {
model: 3 model: 3
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Compass ") + (index + 1) + ":" labelText: qsTr("Compass ") + (index + 1) + ""
valueText: sensorParams.rgCompassAvailable[index] ? valueText: sensorParams.rgCompassAvailable[index] ?
(sensorParams.rgCompassCalibrated[index] ? (sensorParams.rgCompassCalibrated[index] ?
(sensorParams.rgCompassPrimary[index] ? "Primary" : "Secondary") + (sensorParams.rgCompassPrimary[index] ? "Primary" : "Secondary") +
...@@ -47,7 +47,7 @@ FactPanel { ...@@ -47,7 +47,7 @@ FactPanel {
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Accelerometer(s):") labelText: qsTr("Accelerometer(s)")
valueText: controller.accelSetupNeeded ? qsTr("Setup required") : qsTr("Ready") valueText: controller.accelSetupNeeded ? qsTr("Setup required") : qsTr("Ready")
} }
} }
......
...@@ -45,17 +45,17 @@ FactPanel { ...@@ -45,17 +45,17 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
id: nameRow; id: nameRow;
labelText: qsTr("Frame Type:") labelText: qsTr("Frame Type")
valueText: frameName() valueText: frameName()
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Firmware Version:") labelText: qsTr("Firmware Version")
valueText: activeVehicle.firmwareMajorVersion == -1 ? qsTr("Unknown") : activeVehicle.firmwareMajorVersion + "." + activeVehicle.firmwareMinorVersion + "." + activeVehicle.firmwarePatchVersion + " " + activeVehicle.firmwareVersionTypeString valueText: activeVehicle.firmwareMajorVersion == -1 ? qsTr("Unknown") : activeVehicle.firmwareMajorVersion + "." + activeVehicle.firmwareMinorVersion + "." + activeVehicle.firmwarePatchVersion + " " + activeVehicle.firmwareVersionTypeString
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Git Revision:") labelText: qsTr("Git Revision")
valueText: activeVehicle.gitHash == -1 ? qsTr("Unknown") : activeVehicle.gitHash valueText: activeVehicle.gitHash == -1 ? qsTr("Unknown") : activeVehicle.gitHash
} }
} }
......
...@@ -32,20 +32,16 @@ SetupPage { ...@@ -32,20 +32,16 @@ SetupPage {
QGCPalette { id: palette; colorGroupEnabled: true } QGCPalette { id: palette; colorGroupEnabled: true }
// Older firmwares use THR_MODE, newer use MOT_THST_HOVER property bool _rcFeelAvailable: controller.parameterExists(-1, "RC_FEEL")
property bool _throttleMidExists: controller.parameterExists(-1, "THR_MID") property bool _atcInputTCAvailable: controller.parameterExists(-1, "ATC_INPUT_TC")
property Fact _hoverTuneParam: controller.getParameterFact(-1, _throttleMidExists ? "THR_MID" : "MOT_THST_HOVER") property Fact _rcFeel: controller.getParameterFact(-1, "RC_FEEL", false)
property real _hoverTuneMin: _throttleMidExists ? 200 : 0 property Fact _atcInputTC: controller.getParameterFact(-1, "ATC_INPUT_TC", false)
property real _hoverTuneMax: _throttleMidExists ? 800 : 1 property Fact _rateRollP: controller.getParameterFact(-1, "r.ATC_RAT_RLL_P")
property real _hoverTuneStep: _throttleMidExists ? 10 : 0.01 property Fact _rateRollI: controller.getParameterFact(-1, "r.ATC_RAT_RLL_I")
property Fact _ratePitchP: controller.getParameterFact(-1, "r.ATC_RAT_PIT_P")
property Fact _rcFeel: controller.getParameterFact(-1, "RC_FEEL_RP") property Fact _ratePitchI: controller.getParameterFact(-1, "r.ATC_RAT_PIT_I")
property Fact _rateRollP: controller.getParameterFact(-1, "r.ATC_RAT_RLL_P") property Fact _rateClimbP: controller.getParameterFact(-1, "r.PSC_ACCZ_P")
property Fact _rateRollI: controller.getParameterFact(-1, "r.ATC_RAT_RLL_I") property Fact _rateClimbI: controller.getParameterFact(-1, "r.PSC_ACCZ_I")
property Fact _ratePitchP: controller.getParameterFact(-1, "r.ATC_RAT_PIT_P")
property Fact _ratePitchI: controller.getParameterFact(-1, "r.ATC_RAT_PIT_I")
property Fact _rateClimbP: controller.getParameterFact(-1, "ACCEL_Z_P")
property Fact _rateClimbI: controller.getParameterFact(-1, "ACCEL_Z_I")
property Fact _ch7Opt: controller.getParameterFact(-1, "CH7_OPT") property Fact _ch7Opt: controller.getParameterFact(-1, "CH7_OPT")
property Fact _ch8Opt: controller.getParameterFact(-1, "CH8_OPT") property Fact _ch8Opt: controller.getParameterFact(-1, "CH8_OPT")
...@@ -75,10 +71,14 @@ SetupPage { ...@@ -75,10 +71,14 @@ SetupPage {
// handler which updates your property with the new value, this first value change will trash // handler which updates your property with the new value, this first value change will trash
// your bound values. In order to work around this we don't set the values into the Sliders until // your bound values. In order to work around this we don't set the values into the Sliders until
// after Qml load is done. We also don't track value changes until Qml load completes. // after Qml load is done. We also don't track value changes until Qml load completes.
throttleHover.value = _hoverTuneParam.value
rollPitch.value = _rateRollP.value rollPitch.value = _rateRollP.value
climb.value = _rateClimbP.value climb.value = _rateClimbP.value
rcFeel.value = _rcFeel.value if (_rcFeelAvailable) {
rcFeel.value = _rcFeel.value
}
if (_atcInputTCAvailable) {
atcInputTC.value = _atcInputTC.value
}
_loadComplete = true _loadComplete = true
calcAutoTuneChannel() calcAutoTuneChannel()
...@@ -142,36 +142,6 @@ SetupPage { ...@@ -142,36 +142,6 @@ SetupPage {
anchors.top: parent.top anchors.top: parent.top
spacing: _margins spacing: _margins
Column {
anchors.left: parent.left
anchors.right: parent.right
QGCLabel {
text: qsTr("Throttle Hover")
font.family: ScreenTools.demiboldFontFamily
}
QGCLabel {
text: qsTr("How much throttle is needed to maintain a steady hover")
}
Slider {
id: throttleHover
anchors.left: parent.left
anchors.right: parent.right
minimumValue: _hoverTuneMin
maximumValue: _hoverTuneMax
stepSize: _hoverTuneStep
tickmarksEnabled: true
onValueChanged: {
if (_loadComplete) {
_hoverTuneParam.value = value
}
}
}
}
Column { Column {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
...@@ -240,6 +210,7 @@ SetupPage { ...@@ -240,6 +210,7 @@ SetupPage {
Column { Column {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
visible: _rcFeelAvailable
QGCLabel { QGCLabel {
text: qsTr("RC Roll/Pitch Feel") text: qsTr("RC Roll/Pitch Feel")
...@@ -266,6 +237,37 @@ SetupPage { ...@@ -266,6 +237,37 @@ SetupPage {
} }
} }
} }
Column {
anchors.left: parent.left
anchors.right: parent.right
visible: _atcInputTCAvailable
QGCLabel {
text: qsTr("RC Roll/Pitch Feel")
font.family: ScreenTools.demiboldFontFamily
}
QGCLabel {
text: qsTr("Slide to the left for soft control, slide to the right for crisp control")
}
Slider {
id: atcInputTC
anchors.left: parent.left
anchors.right: parent.right
minimumValue: _atcInputTC.min
maximumValue: _atcInputTC.max
stepSize: _atcInputTC.increment
tickmarksEnabled: true
onValueChanged: {
if (_loadComplete) {
_atcInputTC.value = value
}
}
}
}
} }
} // Rectangle - Basic tuning } // Rectangle - Basic tuning
......
...@@ -13,8 +13,6 @@ ...@@ -13,8 +13,6 @@
#include "AutoPilotPlugin.h" #include "AutoPilotPlugin.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "ParameterManager.h"
#include "UAS.h"
#include "FirmwarePlugin.h" #include "FirmwarePlugin.h"
AutoPilotPlugin::AutoPilotPlugin(Vehicle* vehicle, QObject* parent) AutoPilotPlugin::AutoPilotPlugin(Vehicle* vehicle, QObject* parent)
...@@ -28,7 +26,7 @@ AutoPilotPlugin::AutoPilotPlugin(Vehicle* vehicle, QObject* parent) ...@@ -28,7 +26,7 @@ AutoPilotPlugin::AutoPilotPlugin(Vehicle* vehicle, QObject* parent)
AutoPilotPlugin::~AutoPilotPlugin() AutoPilotPlugin::~AutoPilotPlugin()
{ {
} }
void AutoPilotPlugin::_recalcSetupComplete(void) void AutoPilotPlugin::_recalcSetupComplete(void)
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "FactSystem.h" #include "FactSystem.h"
#include "Vehicle.h" #include "Vehicle.h"
class ParameterManager;
class Vehicle; class Vehicle;
class FirmwarePlugin; class FirmwarePlugin;
......
...@@ -30,38 +30,38 @@ FactPanel { ...@@ -30,38 +30,38 @@ FactPanel {
Column { Column {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Firmware Version:") labelText: qsTr("Firmware Version")
valueText: esp8266.version valueText: esp8266.version
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("WiFi Mode:") labelText: qsTr("WiFi Mode")
valueText: wifiMode ? (wifiMode.value === 0 ? "AP Mode" : "Station Mode") : "AP Mode" valueText: wifiMode ? (wifiMode.value === 0 ? "AP Mode" : "Station Mode") : "AP Mode"
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("WiFi Channel:") labelText: qsTr("WiFi Channel")
valueText: wifiChannel ? wifiChannel.valueString : "" valueText: wifiChannel ? wifiChannel.valueString : ""
visible: wifiMode ? wifiMode.value === 0 : true visible: wifiMode ? wifiMode.value === 0 : true
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("WiFi AP SSID:") labelText: qsTr("WiFi AP SSID")
valueText: esp8266.wifiSSID valueText: esp8266.wifiSSID
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("WiFi AP Password:") labelText: qsTr("WiFi AP Password")
valueText: esp8266.wifiPassword valueText: esp8266.wifiPassword
} }
/* Too much info makes it all crammed /* Too much info makes it all crammed
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("WiFi STA SSID:") labelText: qsTr("WiFi STA SSID")
valueText: esp8266.wifiSSIDSta valueText: esp8266.wifiSSIDSta
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("WiFi STA Password:") labelText: qsTr("WiFi STA Password")
valueText: esp8266.wifiPasswordSta valueText: esp8266.wifiPasswordSta
} }
*/ */
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("UART Baud Rate:") labelText: qsTr("UART Baud Rate")
valueText: uartBaud ? uartBaud.valueString : "" valueText: uartBaud ? uartBaud.valueString : ""
} }
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
import QtQuick 2.3 import QtQuick 2.3
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QGroundControl 1.0 import QGroundControl 1.0
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
...@@ -23,21 +24,26 @@ import QGroundControl.Controllers 1.0 ...@@ -23,21 +24,26 @@ import QGroundControl.Controllers 1.0
QGCView { QGCView {
id: setupView id: setupView
viewPanel: setupPanel viewPanel: setupPanel
enabled: !_shouldDisableWhenArmed enabled: !_disableDueToArmed && !_disableDueToFlying
property alias pageComponent: pageLoader.sourceComponent property alias pageComponent: pageLoader.sourceComponent
property string pageName: vehicleComponent ? vehicleComponent.name : "" property string pageName: vehicleComponent ? vehicleComponent.name : ""
property string pageDescription: vehicleComponent ? vehicleComponent.description : "" property string pageDescription: vehicleComponent ? vehicleComponent.description : ""
property real availableWidth: width - pageLoader.x property real availableWidth: width - pageLoader.x
property real availableHeight: height - pageLoader.y property real availableHeight: height - pageLoader.y
property bool showAdvanced: false
property alias advanced: advancedCheckBox.checked
property bool _vehicleArmed: QGroundControl.multiVehicleManager.activeVehicle ? QGroundControl.multiVehicleManager.activeVehicle.armed : false property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property bool _shouldDisableWhenArmed: _vehicleArmed ? (vehicleComponent ? !vehicleComponent.allowSetupWhileArmed : false) : false property bool _vehicleArmed: _activeVehicle ? _activeVehicle.armed : false
property bool _vehicleFlying: _activeVehicle ? _activeVehicle.flying : false
property bool _disableDueToArmed: vehicleComponent ? (!vehicleComponent.allowSetupWhileArmed && _vehicleArmed) : false
property bool _disableDueToFlying: vehicleComponent ? (!vehicleComponent.allowSetupWhileFlying && _vehicleFlying) : false
property string _disableReason: _disableDueToArmed ? qsTr("armed") : qsTr("flying")
property real _margins: ScreenTools.defaultFontPixelHeight * 0.5 property real _margins: ScreenTools.defaultFontPixelHeight * 0.5
property string _pageTitle: qsTr("%1 Setup").arg(pageName) property string _pageTitle: qsTr("%1 Setup").arg(pageName)
QGCPalette { id: qgcPal; colorGroupEnabled: setupPanel.enabled } QGCPalette { id: qgcPal; colorGroupEnabled: setupPanel.enabled }
QGCViewPanel { QGCViewPanel {
...@@ -50,35 +56,49 @@ QGCView { ...@@ -50,35 +56,49 @@ QGCView {
contentHeight: pageLoader.y + pageLoader.item.height contentHeight: pageLoader.y + pageLoader.item.height
clip: true clip: true
Column { RowLayout {
id: headingColumn id: headingRow
width: setupPanel.width anchors.left: parent.left
anchors.right: parent.right
spacing: _margins spacing: _margins
layoutDirection: Qt.RightToLeft
QGCLabel { QGCCheckBox {
font.pointSize: ScreenTools.largeFontPointSize id: advancedCheckBox
text: _shouldDisableWhenArmed ? _pageTitle + "<font color=\"red\">" + qsTr(" (Disabled while the vehicle is armed)") + "</font>" : _pageTitle text: qsTr("Advanced")
visible: !ScreenTools.isShortScreen visible: showAdvanced
} }
QGCLabel { Column {
anchors.left: parent.left spacing: _margins
anchors.right: parent.right Layout.fillWidth: true
wrapMode: Text.WordWrap
text: pageDescription QGCLabel {
visible: !ScreenTools.isShortScreen font.pointSize: ScreenTools.largeFontPointSize
text: !setupView.enabled ? _pageTitle + "<font color=\"red\">" + qsTr(" (Disabled while the vehicle is %1)").arg(_disableReason) + "</font>" : _pageTitle
visible: !ScreenTools.isShortScreen
}
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: pageDescription
visible: !ScreenTools.isShortScreen
}
} }
} }
Loader { Loader {
id: pageLoader id: pageLoader
anchors.topMargin: _margins anchors.topMargin: _margins
anchors.top: headingColumn.bottom anchors.top: headingRow.bottom
} }
// Overlay to display when vehicle is armed and this setup page needs // Overlay to display when vehicle is armed and this setup page needs
// to be disabled // to be disabled
Rectangle { Rectangle {
visible: _shouldDisableWhenArmed visible: !setupView.enabled
anchors.fill: pageLoader anchors.fill: pageLoader
color: "black" color: "black"
opacity: 0.5 opacity: 0.5
......
...@@ -23,20 +23,20 @@ FactPanel { ...@@ -23,20 +23,20 @@ FactPanel {
Column { Column {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("System ID:") labelText: qsTr("System ID")
valueText: sysIdFact ? sysIdFact.valueString : "" valueText: sysIdFact ? sysIdFact.valueString : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Airframe type:") labelText: qsTr("Airframe type")
valueText: autoStartSet ? controller.currentAirframeType : qsTr("Setup required") valueText: autoStartSet ? controller.currentAirframeType : qsTr("Setup required")
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Vehicle:") labelText: qsTr("Vehicle")
valueText: autoStartSet ? controller.currentVehicleName : qsTr("Setup required") valueText: autoStartSet ? controller.currentVehicleName : qsTr("Setup required")
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Firmware Version:") labelText: qsTr("Firmware Version")
valueText: activeVehicle.firmwareMajorVersion === -1 ? qsTr("Unknown") : activeVehicle.firmwareMajorVersion + "." + activeVehicle.firmwareMinorVersion + "." + activeVehicle.firmwarePatchVersion + activeVehicle.firmwareVersionTypeString valueText: activeVehicle.firmwareMajorVersion === -1 ? qsTr("Unknown") : activeVehicle.firmwareMajorVersion + "." + activeVehicle.firmwareMinorVersion + "." + activeVehicle.firmwarePatchVersion + activeVehicle.firmwareVersionTypeString
} }
} }
......
...@@ -329,6 +329,11 @@ ...@@ -329,6 +329,11 @@
<maintainer>Michael Schaeuble</maintainer> <maintainer>Michael Schaeuble</maintainer>
<type>Quadrotor x</type> <type>Quadrotor x</type>
</airframe> </airframe>
<airframe id="4014" maintainer="Lorenz Meier &lt;lorenz@px4.io&gt;" name="S500">
<class>Copter</class>
<maintainer>Lorenz Meier &lt;lorenz@px4.io&gt;</maintainer>
<type>Quadrotor x</type>
</airframe>
<airframe id="4020" maintainer="Thomas Gubler &lt;thomas@px4.io&gt;" name="Hobbyking Micro PCB"> <airframe id="4020" maintainer="Thomas Gubler &lt;thomas@px4.io&gt;" name="Hobbyking Micro PCB">
<class>Copter</class> <class>Copter</class>
<maintainer>Thomas Gubler &lt;thomas@px4.io&gt;</maintainer> <maintainer>Thomas Gubler &lt;thomas@px4.io&gt;</maintainer>
......
...@@ -121,14 +121,14 @@ SetupPage { ...@@ -121,14 +121,14 @@ SetupPage {
} }
QGCLabel { QGCLabel {
anchors.baseline: camTrigCombo.baseline Layout.alignment: Qt.AlignVCenter
text: qsTr("Trigger mode") text: qsTr("Trigger mode")
} }
FactComboBox { FactComboBox {
id: camTrigCombo
fact: _camTriggerMode fact: _camTriggerMode
indexModel: false indexModel: false
enabled: !_rebooting enabled: !_rebooting
Layout.alignment: Qt.AlignVCenter
Layout.minimumWidth: _editFieldWidth Layout.minimumWidth: _editFieldWidth
onActivated: { onActivated: {
applyAndRestart.visible = true applyAndRestart.visible = true
...@@ -136,14 +136,14 @@ SetupPage { ...@@ -136,14 +136,14 @@ SetupPage {
} }
QGCLabel { QGCLabel {
anchors.baseline: camInterfaceCombo.baseline Layout.alignment: Qt.AlignVCenter
text: qsTr("Trigger interface") text: qsTr("Trigger interface")
} }
FactComboBox { FactComboBox {
id: camInterfaceCombo
fact: _camTriggerInterface fact: _camTriggerInterface
indexModel: false indexModel: false
enabled: !_rebooting && (_camTriggerInterface ? true : false) enabled: !_rebooting && (_camTriggerInterface ? true : false)
Layout.alignment: Qt.AlignVCenter
Layout.minimumWidth: _editFieldWidth Layout.minimumWidth: _editFieldWidth
onActivated: { onActivated: {
applyAndRestart.visible = true applyAndRestart.visible = true
...@@ -152,7 +152,7 @@ SetupPage { ...@@ -152,7 +152,7 @@ SetupPage {
QGCLabel { QGCLabel {
text: qsTr("Time Interval") text: qsTr("Time Interval")
anchors.baseline: timeIntervalField.baseline Layout.alignment: Qt.AlignVCenter
color: qgcPal.text color: qgcPal.text
visible: timeIntervalField.visible visible: timeIntervalField.visible
} }
...@@ -161,12 +161,13 @@ SetupPage { ...@@ -161,12 +161,13 @@ SetupPage {
fact: controller.getParameterFact(-1, "TRIG_INTERVAL", false) fact: controller.getParameterFact(-1, "TRIG_INTERVAL", false)
showUnits: true showUnits: true
Layout.minimumWidth: _editFieldWidth Layout.minimumWidth: _editFieldWidth
Layout.alignment: Qt.AlignVCenter
visible: _camTriggerMode.value === 2 visible: _camTriggerMode.value === 2
} }
QGCLabel { QGCLabel {
text: qsTr("Distance Interval") text: qsTr("Distance Interval")
anchors.baseline: trigDistField.baseline Layout.alignment: Qt.AlignVCenter
color: qgcPal.text color: qgcPal.text
visible: trigDistField.visible visible: trigDistField.visible
} }
...@@ -174,6 +175,7 @@ SetupPage { ...@@ -174,6 +175,7 @@ SetupPage {
id: trigDistField id: trigDistField
fact: controller.getParameterFact(-1, "TRIG_DISTANCE", false) fact: controller.getParameterFact(-1, "TRIG_DISTANCE", false)
showUnits: true showUnits: true
Layout.alignment: Qt.AlignVCenter
Layout.minimumWidth: _editFieldWidth Layout.minimumWidth: _editFieldWidth
visible: _camTriggerMode.value === 3 visible: _camTriggerMode.value === 3
} }
...@@ -199,8 +201,8 @@ SetupPage { ...@@ -199,8 +201,8 @@ SetupPage {
} }
Row { Row {
spacing: _margins spacing: _margins
anchors.horizontalCenter: parent.horizontalCenter Layout.alignment: Qt.AlignHCenter
GridLayout { GridLayout {
rows: 2 rows: 2
......
...@@ -25,36 +25,36 @@ FactPanel { ...@@ -25,36 +25,36 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Trigger interface:") labelText: qsTr("Trigger interface")
valueText: _camTriggerInterface ? _camTriggerInterface.enumStringValue : "" valueText: _camTriggerInterface ? _camTriggerInterface.enumStringValue : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Trigger mode:") labelText: qsTr("Trigger mode")
valueText: _camTriggerMode ? _camTriggerMode.enumStringValue : "" valueText: _camTriggerMode ? _camTriggerMode.enumStringValue : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
visible: _timeInterval && _camTriggerMode.value === 2 visible: _timeInterval && _camTriggerMode.value === 2
labelText: qsTr("Time interval:") labelText: qsTr("Time interval")
valueText: _timeInterval ? _timeInterval.value : "" valueText: _timeInterval ? _timeInterval.value : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
visible: _distanceInterval && _camTriggerMode.value === 3 visible: _distanceInterval && _camTriggerMode.value === 3
labelText: qsTr("Distance interval:") labelText: qsTr("Distance interval")
valueText: _distanceInterval ? _distanceInterval.value : "" valueText: _distanceInterval ? _distanceInterval.value : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
visible: _auxPins visible: _auxPins
labelText: qsTr("AUX pins:") labelText: qsTr("AUX pins")
valueText: _auxPins ? _auxPins.value : "" valueText: _auxPins ? _auxPins.value : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
visible: _camTriggerPol visible: _camTriggerPol
labelText: qsTr("AUX pin polarity:") labelText: qsTr("AUX pin polarity")
valueText: _camTriggerPol ? (_camTriggerPol.value ? "High (3.3V)" : "Low (0V)") : "" valueText: _camTriggerPol ? (_camTriggerPol.value ? "High (3.3V)" : "Low (0V)") : ""
} }
......
...@@ -29,13 +29,13 @@ FactPanel { ...@@ -29,13 +29,13 @@ FactPanel {
id: simple id: simple
Column { Column {
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Mode switch:") labelText: qsTr("Mode switch")
valueText: _rcMapFltmode.value === 0 ? qsTr("Setup required") : _rcMapFltmode.enumStringValue valueText: _rcMapFltmode.value === 0 ? qsTr("Setup required") : _rcMapFltmode.enumStringValue
} }
Repeater { Repeater {
model: 6 model: 6
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flight Mode %1 :").arg(index + 1) labelText: qsTr("Flight Mode %1 ").arg(index + 1)
valueText: controller.getParameterFact(-1, "COM_FLTMODE" + (index + 1)).enumStringValue valueText: controller.getParameterFact(-1, "COM_FLTMODE" + (index + 1)).enumStringValue
} }
} }
...@@ -49,19 +49,19 @@ FactPanel { ...@@ -49,19 +49,19 @@ FactPanel {
property Fact loiterSwFact: controller.getParameterFact(-1, "RC_MAP_LOITER_SW") property Fact loiterSwFact: controller.getParameterFact(-1, "RC_MAP_LOITER_SW")
property Fact returnSwFact: controller.getParameterFact(-1, "RC_MAP_RETURN_SW") property Fact returnSwFact: controller.getParameterFact(-1, "RC_MAP_RETURN_SW")
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Mode switch:") labelText: qsTr("Mode switch")
valueText: _rcMapModeSw.value === 0 ? qsTr("Setup required") : _rcMapModeSw.valueString valueText: _rcMapModeSw.value === 0 ? qsTr("Setup required") : _rcMapModeSw.valueString
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Position Ctl switch:") labelText: qsTr("Position Ctl switch")
valueText: posCtlSwFact.value === 0 ? qsTr("Disabled") : posCtlSwFact.valueString valueText: posCtlSwFact.value === 0 ? qsTr("Disabled") : posCtlSwFact.valueString
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Loiter switch:") labelText: qsTr("Loiter switch")
valueText: loiterSwFact.value === 0 ? qsTr("Disabled") : loiterSwFact.valueString valueText: loiterSwFact.value === 0 ? qsTr("Disabled") : loiterSwFact.valueString
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Return switch:") labelText: qsTr("Return switch")
valueText: returnSwFact.value === 0 ? qsTr("Disabled") : returnSwFact.valueString valueText: returnSwFact.value === 0 ? qsTr("Disabled") : returnSwFact.valueString
} }
} }
......
...@@ -26,38 +26,38 @@ FactPanel { ...@@ -26,38 +26,38 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Roll:") labelText: qsTr("Roll")
valueText: mapRollFact ? (mapRollFact.value === 0 ? qsTr("Setup required") : mapRollFact.valueString) : "" valueText: mapRollFact ? (mapRollFact.value === 0 ? qsTr("Setup required") : mapRollFact.valueString) : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Pitch:") labelText: qsTr("Pitch")
valueText: mapPitchFact ? (mapPitchFact.value === 0 ? qsTr("Setup required") : mapPitchFact.valueString) : "" valueText: mapPitchFact ? (mapPitchFact.value === 0 ? qsTr("Setup required") : mapPitchFact.valueString) : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Yaw:") labelText: qsTr("Yaw")
valueText: mapYawFact ? (mapYawFact.value === 0 ? qsTr("Setup required") : mapYawFact.valueString) : "" valueText: mapYawFact ? (mapYawFact.value === 0 ? qsTr("Setup required") : mapYawFact.valueString) : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Throttle:") labelText: qsTr("Throttle")
valueText: mapThrottleFact ? (mapThrottleFact.value === 0 ? qsTr("Setup required") : mapThrottleFact.valueString) : "" valueText: mapThrottleFact ? (mapThrottleFact.value === 0 ? qsTr("Setup required") : mapThrottleFact.valueString) : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Flaps:") labelText: qsTr("Flaps")
valueText: mapFlapsFact ? (mapFlapsFact.value === 0 ? qsTr("Disabled") : mapFlapsFact.valueString) : "" valueText: mapFlapsFact ? (mapFlapsFact.value === 0 ? qsTr("Disabled") : mapFlapsFact.valueString) : ""
visible: !controller.vehicle.multiRotor visible: !controller.vehicle.multiRotor
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Aux1:") labelText: qsTr("Aux1")
valueText: mapAux1Fact ? (mapAux1Fact.value === 0 ? qsTr("Disabled") : mapAux1Fact.valueString) : "" valueText: mapAux1Fact ? (mapAux1Fact.value === 0 ? qsTr("Disabled") : mapAux1Fact.valueString) : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Aux2:") labelText: qsTr("Aux2")
valueText: mapAux2Fact ? (mapAux2Fact.value === 0 ? qsTr("Disabled") : mapAux2Fact.valueString) : "" valueText: mapAux2Fact ? (mapAux2Fact.value === 0 ? qsTr("Disabled") : mapAux2Fact.valueString) : ""
} }
} }
......
...@@ -32,6 +32,7 @@ public: ...@@ -32,6 +32,7 @@ public:
QUrl setupSource(void) const final; QUrl setupSource(void) const final;
QUrl summaryQmlSource(void) const final; QUrl summaryQmlSource(void) const final;
bool allowSetupWhileArmed(void) const final { return true; } bool allowSetupWhileArmed(void) const final { return true; }
bool allowSetupWhileFlying(void) const final { return true; }
private: private:
const QString _name; const QString _name;
......
...@@ -7,11 +7,16 @@ ...@@ -7,11 +7,16 @@
* *
****************************************************************************/ ****************************************************************************/
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtCharts 2.2
import QtQuick.Layouts 1.2
import QtQuick 2.3 import QGroundControl 1.0
import QtQuick.Controls 1.2 import QGroundControl.Controls 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.Controls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.ScreenTools 1.0
SetupPage { SetupPage {
id: tuningPage id: tuningPage
...@@ -20,47 +25,97 @@ SetupPage { ...@@ -20,47 +25,97 @@ SetupPage {
Component { Component {
id: pageComponent id: pageComponent
FactSliderPanel { Column {
width: availableWidth width: availableWidth
qgcViewPanel: tuningPage.viewPanel
sliderModel: ListModel { Component.onCompleted: {
ListElement { showAdvanced = !ScreenTools.isMobile
title: qsTr("Hover Throttle") }
description: qsTr("Adjust throttle so hover is at mid-throttle. Slide to the left if hover is lower than throttle center. Slide to the right if hover is higher than throttle center.")
param: "MPC_THR_HOVER"
min: 20
max: 80
step: 1
}
ListElement { FactPanelController {
title: qsTr("Manual minimum throttle") id: controller
description: qsTr("Slide to the left to start the motors with less idle power. Slide to the right if descending in manual flight becomes unstable.") factPanel: tuningPage.viewPanel
param: "MPC_MANTHR_MIN" }
min: 0
max: 15
step: 1
}
ListElement { // Standard tuning page
title: qsTr("Roll sensitivity") FactSliderPanel {
description: qsTr("Slide to the left to make roll control faster and more accurate. Slide to the right if roll oscillates or is too twitchy.") width: availableWidth
param: "MC_ROLL_TC" qgcViewPanel: tuningPage.viewPanel
min: 0.15 visible: !advanced
max: 0.25
step: 0.01 sliderModel: ListModel {
} ListElement {
title: qsTr("Hover Throttle")
description: qsTr("Adjust throttle so hover is at mid-throttle. Slide to the left if hover is lower than throttle center. Slide to the right if hover is higher than throttle center.")
param: "MPC_THR_HOVER"
min: 20
max: 80
step: 1
}
ListElement { ListElement {
title: qsTr("Pitch sensitivity") title: qsTr("Manual minimum throttle")
description: qsTr("Slide to the left to make pitch control faster and more accurate. Slide to the right if pitch oscillates or is too twitchy.") description: qsTr("Slide to the left to start the motors with less idle power. Slide to the right if descending in manual flight becomes unstable.")
param: "MC_PITCH_TC" param: "MPC_MANTHR_MIN"
min: 0.15 min: 0
max: 0.25 max: 15
step: 0.01 step: 1
}
/*
These seem to have disappeared from PX4 firmware!
ListElement {
title: qsTr("Roll sensitivity")
description: qsTr("Slide to the left to make roll control faster and more accurate. Slide to the right if roll oscillates or is too twitchy.")
param: "MC_ROLL_TC"
min: 0.15
max: 0.25
step: 0.01
}
ListElement {
title: qsTr("Pitch sensitivity")
description: qsTr("Slide to the left to make pitch control faster and more accurate. Slide to the right if pitch oscillates or is too twitchy.")
param: "MC_PITCH_TC"
min: 0.15
max: 0.25
step: 0.01
}
*/
} }
} }
}
} // Component Loader {
anchors.left: parent.left
anchors.right: parent.right
sourceComponent: advanced ? advancePageComponent : undefined
}
Component {
id: advancePageComponent
PIDTuning {
anchors.left: parent.left
anchors.right: parent.right
tuneList: [ qsTr("Roll"), qsTr("Pitch"), qsTr("Yaw") ]
params: [
[ controller.getParameterFact(-1, "MC_ROLL_P"),
controller.getParameterFact(-1, "MC_ROLLRATE_P"),
controller.getParameterFact(-1, "MC_ROLLRATE_I"),
controller.getParameterFact(-1, "MC_ROLLRATE_D"),
controller.getParameterFact(-1, "MC_ROLLRATE_FF") ],
[ controller.getParameterFact(-1, "MC_PITCH_P"),
controller.getParameterFact(-1, "MC_PITCHRATE_P"),
controller.getParameterFact(-1, "MC_PITCHRATE_I"),
controller.getParameterFact(-1, "MC_PITCHRATE_D"),
controller.getParameterFact(-1, "MC_PITCHRATE_FF") ],
[ controller.getParameterFact(-1, "MC_YAW_P"),
controller.getParameterFact(-1, "MC_YAWRATE_P"),
controller.getParameterFact(-1, "MC_YAWRATE_I"),
controller.getParameterFact(-1, "MC_YAWRATE_D"),
controller.getParameterFact(-1, "MC_YAW_FF"),
controller.getParameterFact(-1, "MC_YAWRATE_FF") ] ]
}
} // Component - Advanced Page
} // Column
} // Component - pageComponent
} // SetupPage } // SetupPage
...@@ -7,11 +7,16 @@ ...@@ -7,11 +7,16 @@
* *
****************************************************************************/ ****************************************************************************/
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtCharts 2.2
import QtQuick.Layouts 1.2
import QtQuick 2.3 import QGroundControl 1.0
import QtQuick.Controls 1.2 import QGroundControl.Controls 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.Controls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.ScreenTools 1.0
SetupPage { SetupPage {
id: tuningPage id: tuningPage
...@@ -20,47 +25,64 @@ SetupPage { ...@@ -20,47 +25,64 @@ SetupPage {
Component { Component {
id: pageComponent id: pageComponent
FactSliderPanel { Column {
width: availableWidth width: availableWidth
qgcViewPanel: tuningPage.viewPanel
sliderModel: ListModel { Component.onCompleted: {
ListElement { showAdvanced = !ScreenTools.isMobile
title: qsTr("Roll sensitivity") }
description: qsTr("Slide to the left to make roll control faster and more accurate. Slide to the right if roll oscillates or is too twitchy.")
param: "FW_R_TC"
min: 0.2
max: 0.8
step: 0.01
}
ListElement { FactPanelController {
title: qsTr("Pitch sensitivity") id: controller
description: qsTr("Slide to the left to make pitch control faster and more accurate. Slide to the right if pitch oscillates or is too twitchy.") factPanel: tuningPage.viewPanel
param: "FW_P_TC" }
min: 0.2
max: 0.8
step: 0.01
}
ListElement { // Standard tuning page
title: qsTr("Cruise throttle") FactSliderPanel {
description: qsTr("This is the throttle setting required to achieve the desired cruise speed. Most planes need 50-60%.") width: availableWidth
param: "FW_THR_CRUISE" qgcViewPanel: tuningPage.viewPanel
min: 20 visible: !advanced
max: 80
step: 1
}
ListElement { sliderModel: ListModel {
title: qsTr("Mission mode sensitivity") ListElement {
description: qsTr("Slide to the left to make position control more accurate and more aggressive. Slide to the right to make flight in mission mode smoother and less twitchy.") title: qsTr("Cruise throttle")
param: "FW_L1_PERIOD" description: qsTr("This is the throttle setting required to achieve the desired cruise speed. Most planes need 50-60%.")
min: 12 param: "FW_THR_CRUISE"
max: 50 min: 20
step: 0.5 max: 80
step: 1
}
} }
} }
}
}
} Loader {
anchors.left: parent.left
anchors.right: parent.right
sourceComponent: advanced ? advancePageComponent : undefined
}
Component {
id: advancePageComponent
PIDTuning {
anchors.left: parent.left
anchors.right: parent.right
tuneList: [ qsTr("Roll"), qsTr("Pitch"), qsTr("Yaw") ]
params: [
[ controller.getParameterFact(-1, "FW_RR_P"),
controller.getParameterFact(-1, "FW_RR_I"),
controller.getParameterFact(-1, "FW_RR_FF"),
controller.getParameterFact(-1, "FW_R_TC"),],
[ controller.getParameterFact(-1, "FW_PR_P"),
controller.getParameterFact(-1, "FW_PR_I"),
controller.getParameterFact(-1, "FW_PR_FF"),
controller.getParameterFact(-1, "FW_P_TC") ],
[ controller.getParameterFact(-1, "FW_YR_P"),
controller.getParameterFact(-1, "FW_YR_I"),
controller.getParameterFact(-1, "FW_YR_FF") ] ]
}
} // Component - Advanced Page
} // Column
} // Component - pageComponent
} // SetupPage
...@@ -26,24 +26,6 @@ SetupPage { ...@@ -26,24 +26,6 @@ SetupPage {
sliderModel: ListModel { sliderModel: ListModel {
ListElement {
title: qsTr("Hover Roll sensitivity")
description: qsTr("Slide to the left to make roll control during hover faster and more accurate. Slide to the right if roll oscillates or is too twitchy.")
param: "MC_ROLL_TC"
min: 0.15
max: 0.25
step: 0.01
}
ListElement {
title: qsTr("Hover Pitch sensitivity")
description: qsTr("Slide to the left to make pitch control during hover faster and more accurate. Slide to the right if pitch oscillates or is too twitchy.")
param: "MC_PITCH_TC"
min: 0.15
max: 0.25
step: 0.01
}
ListElement { ListElement {
title: qsTr("Plane Roll sensitivity") title: qsTr("Plane Roll sensitivity")
description: qsTr("Slide to the left to make roll control faster and more accurate. Slide to the right if roll oscillates or is too twitchy.") description: qsTr("Slide to the left to make roll control faster and more accurate. Slide to the right if roll oscillates or is too twitchy.")
...@@ -81,7 +63,7 @@ SetupPage { ...@@ -81,7 +63,7 @@ SetupPage {
} }
ListElement { ListElement {
title: qsTr("Hoever manual minimum throttle") title: qsTr("Hover manual minimum throttle")
description: qsTr("Slide to the left to start the motors with less idle power. Slide to the right if descending in manual flight becomes unstable.") description: qsTr("Slide to the left to start the motors with less idle power. Slide to the right if descending in manual flight becomes unstable.")
param: "MPC_MANTHR_MIN" param: "MPC_MANTHR_MIN"
min: 0 min: 0
......
...@@ -24,18 +24,19 @@ class PowerComponent : public VehicleComponent ...@@ -24,18 +24,19 @@ class PowerComponent : public VehicleComponent
public: public:
PowerComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL); PowerComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent = NULL);
// Virtuals from VehicleComponent // Overrides from VehicleComponent
virtual QStringList setupCompleteChangedTriggerList(void) const; QStringList setupCompleteChangedTriggerList(void) const override;
// Virtuals from VehicleComponent
virtual QString name (void) const;
virtual QString description (void) const;
virtual QString iconResource (void) const;
virtual bool requiresSetup (void) const;
virtual bool setupComplete (void) const;
virtual QUrl setupSource (void) const;
virtual QUrl summaryQmlSource (void) const;
// Overrides from VehicleComponent
QString name (void) const override;
QString description (void) const override;
QString iconResource (void) const override;
bool requiresSetup (void) const override;
bool setupComplete (void) const override;
QUrl setupSource (void) const override;
QUrl summaryQmlSource (void) const override;
bool allowSetupWhileArmed (void) const override { return true; }
private: private:
const QString _name; const QString _name;
QVariantList _summaryItems; QVariantList _summaryItems;
......
...@@ -348,9 +348,9 @@ SetupPage { ...@@ -348,9 +348,9 @@ SetupPage {
} // QGCGroupBox - Battery settings } // QGCGroupBox - Battery settings
QGCGroupBox { QGCGroupBox {
anchors.left: batteryGroup.left Layout.maximumWidth: batteryGroup.width
anchors.right: batteryGroup.right Layout.fillWidth: true
title: qsTr("ESC PWM Minimum and Maximum Calibration") title: qsTr("ESC PWM Minimum and Maximum Calibration")
ColumnLayout { ColumnLayout {
anchors.left: parent.left anchors.left: parent.left
...@@ -383,10 +383,10 @@ SetupPage { ...@@ -383,10 +383,10 @@ SetupPage {
} }
QGCGroupBox { QGCGroupBox {
anchors.left: batteryGroup.left Layout.maximumWidth: batteryGroup.width
anchors.right: batteryGroup.right Layout.fillWidth: true
title: qsTr("UAVCAN Bus Configuration") title: qsTr("UAVCAN Bus Configuration")
visible: showUAVCAN.checked visible: showUAVCAN.checked
Row { Row {
id: uavCanConfigRow id: uavCanConfigRow
...@@ -407,10 +407,10 @@ SetupPage { ...@@ -407,10 +407,10 @@ SetupPage {
} }
QGCGroupBox { QGCGroupBox {
anchors.left: batteryGroup.left Layout.maximumWidth: batteryGroup.width
anchors.right: batteryGroup.right Layout.fillWidth: true
title: qsTr("UAVCAN Motor Index and Direction Assignment") title: qsTr("UAVCAN Motor Index and Direction Assignment")
visible: showUAVCAN.checked visible: showUAVCAN.checked
ColumnLayout { ColumnLayout {
anchors.left: parent.left anchors.left: parent.left
...@@ -456,10 +456,10 @@ SetupPage { ...@@ -456,10 +456,10 @@ SetupPage {
} }
QGCGroupBox { QGCGroupBox {
anchors.left: batteryGroup.left Layout.maximumWidth: batteryGroup.width
anchors.right: batteryGroup.right Layout.fillWidth: true
title: qsTr("Advanced Power Settings") title: qsTr("Advanced Power Settings")
visible: showAdvanced.checked visible: showAdvanced.checked
ColumnLayout { ColumnLayout {
anchors.left: parent.left anchors.left: parent.left
...@@ -487,7 +487,7 @@ SetupPage { ...@@ -487,7 +487,7 @@ SetupPage {
text: qsTr("Batteries show less voltage at high throttle. Enter the difference in Volts between idle throttle and full ") + text: qsTr("Batteries show less voltage at high throttle. Enter the difference in Volts between idle throttle and full ") +
qsTr("throttle, divided by the number of battery cells. Leave at the default if unsure. ") + qsTr("throttle, divided by the number of battery cells. Leave at the default if unsure. ") +
highlightPrefix + qsTr("If this value is set too high, the battery might be deep discharged and damaged.") + highlightSuffix highlightPrefix + qsTr("If this value is set too high, the battery might be deep discharged and damaged.") + highlightSuffix
Layout.fillWidth: true Layout.maximumWidth: ScreenTools.defaultFontPixelWidth * 60
} }
Row { Row {
......
...@@ -36,17 +36,17 @@ FactPanel { ...@@ -36,17 +36,17 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Battery Full:") labelText: qsTr("Battery Full")
valueText: batVChargedFact ? batVChargedFact.valueString + " " + batVChargedFact.units : "" valueText: batVChargedFact ? batVChargedFact.valueString + " " + batVChargedFact.units : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Battery Empty:") labelText: qsTr("Battery Empty")
valueText: batVEmptyFact ? batVEmptyFact.valueString + " " + batVEmptyFact.units : "" valueText: batVEmptyFact ? batVEmptyFact.valueString + " " + batVEmptyFact.units : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Number of Cells:") labelText: qsTr("Number of Cells")
valueText: batCellsFact ? batCellsFact.valueString : "" valueText: batCellsFact ? batCellsFact.valueString : ""
} }
} }
......
...@@ -14,46 +14,64 @@ FactPanel { ...@@ -14,46 +14,64 @@ FactPanel {
QGCPalette { id: qgcPal; colorGroupEnabled: enabled } QGCPalette { id: qgcPal; colorGroupEnabled: enabled }
FactPanelController { id: controller; factPanel: panel } FactPanelController { id: controller; factPanel: panel }
property Fact returnAltFact: controller.getParameterFact(-1, "RTL_RETURN_ALT") property Fact returnAltFact: controller.getParameterFact(-1, "RTL_RETURN_ALT")
property Fact descendAltFact: controller.getParameterFact(-1, "RTL_DESCEND_ALT") property Fact _descendAltFact: controller.getParameterFact(-1, "RTL_DESCEND_ALT")
property Fact landDelayFact: controller.getParameterFact(-1, "RTL_LAND_DELAY") property Fact landDelayFact: controller.getParameterFact(-1, "RTL_LAND_DELAY")
property Fact commRCLossFact: controller.getParameterFact(-1, "COM_RC_LOSS_T") property Fact commRCLossFact: controller.getParameterFact(-1, "COM_RC_LOSS_T")
property Fact lowBattAction: controller.getParameterFact(-1, "COM_LOW_BAT_ACT") property Fact lowBattAction: controller.getParameterFact(-1, "COM_LOW_BAT_ACT")
property Fact rcLossAction: controller.getParameterFact(-1, "NAV_RCL_ACT") property Fact rcLossAction: controller.getParameterFact(-1, "NAV_RCL_ACT")
property Fact dataLossAction: controller.getParameterFact(-1, "NAV_DLL_ACT") property Fact dataLossAction: controller.getParameterFact(-1, "NAV_DLL_ACT")
property Fact _rtlLandDelayFact: controller.getParameterFact(-1, "RTL_LAND_DELAY")
property int _rtlLandDelayValue: _rtlLandDelayFact.value
Column { Column {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("RTL min alt:") labelText: qsTr("Low Battery Failsafe")
valueText: returnAltFact ? returnAltFact.valueString + " " + returnAltFact.units : "" valueText: lowBattAction ? lowBattAction.enumStringValue : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("RTL home alt:") labelText: qsTr("RC Loss Failsafe")
valueText: descendAltFact ? descendAltFact.valueString + " " + descendAltFact.units : "" valueText: rcLossAction ? rcLossAction.enumStringValue : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("RC loss RTL:") labelText: qsTr("RC Loss Timeout")
valueText: commRCLossFact ? commRCLossFact.valueString + " " + commRCLossFact.units : "" valueText: commRCLossFact ? commRCLossFact.valueString + " " + commRCLossFact.units : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("RC loss action:") labelText: qsTr("Data Link Loss Failsafe")
valueText: rcLossAction ? rcLossAction.enumStringValue : "" valueText: dataLossAction ? dataLossAction.enumStringValue : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Link loss action:") labelText: qsTr("RTL Climb To")
valueText: dataLossAction ? dataLossAction.enumStringValue : "" valueText: returnAltFact ? returnAltFact.valueString + " " + returnAltFact.units : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Low battery action:") labelText: qsTr("RTL, Then")
valueText: lowBattAction ? lowBattAction.enumStringValue : "" valueText: _rtlLandDelayValue === 0 ?
qsTr("Land immediately") :
(_rtlLandDelayValue < 0 ?
qsTr("Loiter and do not land") :
qsTr("Loiter and land after specified time"))
} }
VehicleSummaryRow {
labelText: qsTr("Loiter Alt")
valueText: _descendAltFact.valueString + " " + _descendAltFact.units
visible: _rtlLandDelayValue !== 0
}
VehicleSummaryRow {
labelText: qsTr("Land Delay")
valueText: _rtlLandDelayValue + " " + _rtlLandDelayFact.units
visible: _rtlLandDelayValue > 0
}
} }
} }
...@@ -20,11 +20,14 @@ const char* SensorsComponent::_airspeedBreakerParam = "CBRK_AIRSPD_CHK"; ...@@ -20,11 +20,14 @@ const char* SensorsComponent::_airspeedBreakerParam = "CBRK_AIRSPD_CHK";
const char* SensorsComponent::_airspeedDisabledParam = "FW_ARSP_MODE"; const char* SensorsComponent::_airspeedDisabledParam = "FW_ARSP_MODE";
const char* SensorsComponent::_airspeedCalParam = "SENS_DPRES_OFF"; const char* SensorsComponent::_airspeedCalParam = "SENS_DPRES_OFF";
const char* SensorsComponent::_magEnabledParam = "SYS_HAS_MAG";
const char* SensorsComponent::_magCalParam = "CAL_MAG0_ID";
SensorsComponent::SensorsComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent) : SensorsComponent::SensorsComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent) :
VehicleComponent(vehicle, autopilot, parent), VehicleComponent(vehicle, autopilot, parent),
_name(tr("Sensors")) _name(tr("Sensors"))
{ {
_deviceIds << QStringLiteral("CAL_MAG0_ID") << QStringLiteral("CAL_GYRO0_ID") << QStringLiteral("CAL_ACC0_ID"); _deviceIds << QStringLiteral("CAL_GYRO0_ID") << QStringLiteral("CAL_ACC0_ID");
} }
QString SensorsComponent::name(void) const QString SensorsComponent::name(void) const
...@@ -54,6 +57,14 @@ bool SensorsComponent::setupComplete(void) const ...@@ -54,6 +57,14 @@ bool SensorsComponent::setupComplete(void) const
return false; return false;
} }
} }
bool magEnabled = true;
if (_vehicle->parameterManager()->parameterExists(FactSystem::defaultComponentId, _magEnabledParam)) {
magEnabled = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, _magEnabledParam)->rawValue().toBool();
}
if (magEnabled && _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, _magCalParam)->rawValue().toFloat() == 0.0f) {
return false;
}
if (_vehicle->fixedWing() || _vehicle->vtol()) { if (_vehicle->fixedWing() || _vehicle->vtol()) {
if (!_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, _airspeedDisabledParam)->rawValue().toBool() && if (!_vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, _airspeedDisabledParam)->rawValue().toBool() &&
...@@ -70,7 +81,7 @@ QStringList SensorsComponent::setupCompleteChangedTriggerList(void) const ...@@ -70,7 +81,7 @@ QStringList SensorsComponent::setupCompleteChangedTriggerList(void) const
{ {
QStringList triggers; QStringList triggers;
triggers << _deviceIds; triggers << _deviceIds << _magCalParam << _magEnabledParam;
if (_vehicle->fixedWing() || _vehicle->vtol()) { if (_vehicle->fixedWing() || _vehicle->vtol()) {
triggers << _airspeedCalParam << _airspeedBreakerParam; triggers << _airspeedCalParam << _airspeedBreakerParam;
} }
......
...@@ -44,6 +44,9 @@ private: ...@@ -44,6 +44,9 @@ private:
static const char* _airspeedDisabledParam; static const char* _airspeedDisabledParam;
static const char* _airspeedBreakerParam; static const char* _airspeedBreakerParam;
static const char* _airspeedCalParam; static const char* _airspeedCalParam;
static const char* _magEnabledParam;
static const char* _magCalParam;
}; };
#endif #endif
...@@ -7,10 +7,6 @@ ...@@ -7,10 +7,6 @@
* *
****************************************************************************/ ****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "SensorsComponentController.h" #include "SensorsComponentController.h"
#include "QGCMAVLink.h" #include "QGCMAVLink.h"
#include "UAS.h" #include "UAS.h"
...@@ -22,46 +18,48 @@ ...@@ -22,46 +18,48 @@
QGC_LOGGING_CATEGORY(SensorsComponentControllerLog, "SensorsComponentControllerLog") QGC_LOGGING_CATEGORY(SensorsComponentControllerLog, "SensorsComponentControllerLog")
SensorsComponentController::SensorsComponentController(void) : SensorsComponentController::SensorsComponentController(void)
_statusLog(NULL), : _statusLog (NULL)
_progressBar(NULL), , _progressBar (NULL)
_compassButton(NULL), , _compassButton (NULL)
_gyroButton(NULL), , _gyroButton (NULL)
_accelButton(NULL), , _accelButton (NULL)
_airspeedButton(NULL), , _airspeedButton (NULL)
_levelButton(NULL), , _levelButton (NULL)
_cancelButton(NULL), , _cancelButton (NULL)
_setOrientationsButton(NULL), , _setOrientationsButton (NULL)
_showOrientationCalArea(false), , _showOrientationCalArea (false)
_gyroCalInProgress(false), , _gyroCalInProgress (false)
_magCalInProgress(false), , _magCalInProgress (false)
_accelCalInProgress(false), , _accelCalInProgress (false)
_orientationCalDownSideDone(false), , _airspeedCalInProgress (false)
_orientationCalUpsideDownSideDone(false), , _levelCalInProgress (false)
_orientationCalLeftSideDone(false), , _orientationCalDownSideDone (false)
_orientationCalRightSideDone(false), , _orientationCalUpsideDownSideDone (false)
_orientationCalNoseDownSideDone(false), , _orientationCalLeftSideDone (false)
_orientationCalTailDownSideDone(false), , _orientationCalRightSideDone (false)
_orientationCalDownSideVisible(false), , _orientationCalNoseDownSideDone (false)
_orientationCalUpsideDownSideVisible(false), , _orientationCalTailDownSideDone (false)
_orientationCalLeftSideVisible(false), , _orientationCalDownSideVisible (false)
_orientationCalRightSideVisible(false), , _orientationCalUpsideDownSideVisible (false)
_orientationCalNoseDownSideVisible(false), , _orientationCalLeftSideVisible (false)
_orientationCalTailDownSideVisible(false), , _orientationCalRightSideVisible (false)
_orientationCalDownSideInProgress(false), , _orientationCalNoseDownSideVisible (false)
_orientationCalUpsideDownSideInProgress(false), , _orientationCalTailDownSideVisible (false)
_orientationCalLeftSideInProgress(false), , _orientationCalDownSideInProgress (false)
_orientationCalRightSideInProgress(false), , _orientationCalUpsideDownSideInProgress (false)
_orientationCalNoseDownSideInProgress(false), , _orientationCalLeftSideInProgress (false)
_orientationCalTailDownSideInProgress(false), , _orientationCalRightSideInProgress (false)
_orientationCalDownSideRotate(false), , _orientationCalNoseDownSideInProgress (false)
_orientationCalUpsideDownSideRotate(false), , _orientationCalTailDownSideInProgress (false)
_orientationCalLeftSideRotate(false), , _orientationCalDownSideRotate (false)
_orientationCalRightSideRotate(false), , _orientationCalUpsideDownSideRotate (false)
_orientationCalNoseDownSideRotate(false), , _orientationCalLeftSideRotate (false)
_orientationCalTailDownSideRotate(false), , _orientationCalRightSideRotate (false)
_unknownFirmwareVersion(false), , _orientationCalNoseDownSideRotate (false)
_waitingForCancel(false) , _orientationCalTailDownSideRotate (false)
, _unknownFirmwareVersion (false)
, _waitingForCancel (false)
{ {
} }
...@@ -165,7 +163,9 @@ void SensorsComponentController::_stopCalibration(SensorsComponentController::St ...@@ -165,7 +163,9 @@ void SensorsComponentController::_stopCalibration(SensorsComponentController::St
switch (code) { switch (code) {
case StopCalibrationSuccess: case StopCalibrationSuccess:
_orientationCalAreaHelpText->setProperty("text", tr("Calibration complete")); _orientationCalAreaHelpText->setProperty("text", tr("Calibration complete"));
emit resetStatusTextArea(); if (!_airspeedCalInProgress && !_levelCalInProgress) {
emit resetStatusTextArea();
}
if (_magCalInProgress) { if (_magCalInProgress) {
emit setCompassRotations(); emit setCompassRotations();
} }
...@@ -186,6 +186,7 @@ void SensorsComponentController::_stopCalibration(SensorsComponentController::St ...@@ -186,6 +186,7 @@ void SensorsComponentController::_stopCalibration(SensorsComponentController::St
_magCalInProgress = false; _magCalInProgress = false;
_accelCalInProgress = false; _accelCalInProgress = false;
_gyroCalInProgress = false; _gyroCalInProgress = false;
_airspeedCalInProgress = false;
} }
void SensorsComponentController::calibrateGyro(void) void SensorsComponentController::calibrateGyro(void)
...@@ -336,6 +337,10 @@ void SensorsComponentController::_handleUASTextMessage(int uasId, int compId, in ...@@ -336,6 +337,10 @@ void SensorsComponentController::_handleUASTextMessage(int uasId, int compId, in
emit orientationCalSidesVisibleChanged(); emit orientationCalSidesVisibleChanged();
emit orientationCalSidesInProgressChanged(); emit orientationCalSidesInProgressChanged();
_updateAndEmitShowOrientationCalArea(true); _updateAndEmitShowOrientationCalArea(true);
} else if (text == "airspeed") {
_airspeedCalInProgress = true;
} else if (text == "level") {
_levelCalInProgress = true;
} }
return; return;
} }
......
...@@ -131,7 +131,9 @@ private: ...@@ -131,7 +131,9 @@ private:
bool _gyroCalInProgress; bool _gyroCalInProgress;
bool _magCalInProgress; bool _magCalInProgress;
bool _accelCalInProgress; bool _accelCalInProgress;
bool _airspeedCalInProgress;
bool _levelCalInProgress;
bool _orientationCalDownSideDone; bool _orientationCalDownSideDone;
bool _orientationCalUpsideDownSideDone; bool _orientationCalUpsideDownSideDone;
bool _orientationCalLeftSideDone; bool _orientationCalLeftSideDone;
......
...@@ -29,29 +29,29 @@ FactPanel { ...@@ -29,29 +29,29 @@ FactPanel {
anchors.fill: parent anchors.fill: parent
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Compass 0:") labelText: qsTr("Compass 0")
valueText: mag0IdFact ? (mag0IdFact.value === 0 ? qsTr("Setup required") : qsTr("Ready")) : "" valueText: mag0IdFact ? (mag0IdFact.value === 0 ? qsTr("Setup required") : qsTr("Ready")) : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Compass 1:") labelText: qsTr("Compass 1")
visible: mag1IdFact.value !== 0 visible: mag1IdFact.value !== 0
valueText: qsTr("Ready") valueText: qsTr("Ready")
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Compass 2:") labelText: qsTr("Compass 2")
visible: mag2IdFact.value !== 0 visible: mag2IdFact.value !== 0
valueText: qsTr("Ready") valueText: qsTr("Ready")
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Gyro:") labelText: qsTr("Gyro")
valueText: gyro0IdFact ? (gyro0IdFact.value === 0 ? qsTr("Setup required") : qsTr("Ready")) : "" valueText: gyro0IdFact ? (gyro0IdFact.value === 0 ? qsTr("Setup required") : qsTr("Ready")) : ""
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: qsTr("Accelerometer:") labelText: qsTr("Accelerometer")
valueText: accel0IdFact ? (accel0IdFact.value === 0 ? qsTr("Setup required") : qsTr("Ready")) : "" valueText: accel0IdFact ? (accel0IdFact.value === 0 ? qsTr("Setup required") : qsTr("Ready")) : ""
} }
} }
......
...@@ -25,7 +25,7 @@ FactPanel { ...@@ -25,7 +25,7 @@ FactPanel {
property Fact airspeedDisabledFact: controller.getParameterFact(-1, "FW_ARSP_MODE") property Fact airspeedDisabledFact: controller.getParameterFact(-1, "FW_ARSP_MODE")
property Fact airspeedBreakerFact: controller.getParameterFact(-1, "CBRK_AIRSPD_CHK") property Fact airspeedBreakerFact: controller.getParameterFact(-1, "CBRK_AIRSPD_CHK")
property bool _airspeedVisible: airspeedDisabledFact.value === false && airspeedBreakerFact.value !== 162128 property bool _airspeedVisible: airspeedDisabledFact.value == 0 && airspeedBreakerFact.value !== 162128
property bool _airspeedCalRequired: _airspeedVisible && dpressOffFact.value === 0 property bool _airspeedCalRequired: _airspeedVisible && dpressOffFact.value === 0
Column { Column {
......
...@@ -140,9 +140,7 @@ Item { ...@@ -140,9 +140,7 @@ Item {
onWaitingForCancelChanged: { onWaitingForCancelChanged: {
if (controller.waitingForCancel) { if (controller.waitingForCancel) {
showMessage(qsTr("Calibration Cancel"), qsTr("Waiting for Vehicle to response to Cancel. This may take a few seconds."), 0) showDialog(waitForCancelDialogComponent, qsTr("Calibration Cancel"), qgcView.showDialogDefaultWidth, 0)
} else {
hideDialog()
} }
} }
} }
...@@ -154,6 +152,24 @@ Item { ...@@ -154,6 +152,24 @@ Item {
} }
} }
Component {
id: waitForCancelDialogComponent
QGCViewMessage {
message: qsTr("Waiting for Vehicle to response to Cancel. This may take a few seconds.")
Connections {
target: controller
onWaitingForCancelChanged: {
if (!controller.waitingForCancel) {
hideDialog()
}
}
}
}
}
Component { Component {
id: preCalibrationDialogComponent id: preCalibrationDialogComponent
...@@ -349,11 +365,12 @@ Item { ...@@ -349,11 +365,12 @@ Item {
spacing: ScreenTools.defaultFontPixelHeight / 2 spacing: ScreenTools.defaultFontPixelHeight / 2
IndicatorButton { IndicatorButton {
property bool _hasMag: controller.parameterExists(-1, "SYS_HAS_MAG") ? controller.getParameterFact(-1, "SYS_HAS_MAG").value !== 0 : true
id: compassButton id: compassButton
width: _buttonWidth width: _buttonWidth
text: qsTr("Compass") text: qsTr("Compass")
indicatorGreen: cal_mag0_id.value !== 0 indicatorGreen: cal_mag0_id.value !== 0
visible: QGroundControl.corePlugin.options.showSensorCalibrationCompass && showSensorCalibrationCompass visible: _hasMag && QGroundControl.corePlugin.options.showSensorCalibrationCompass && showSensorCalibrationCompass
onClicked: { onClicked: {
preCalibrationDialogType = "compass" preCalibrationDialogType = "compass"
...@@ -410,7 +427,7 @@ Item { ...@@ -410,7 +427,7 @@ Item {
width: _buttonWidth width: _buttonWidth
text: qsTr("Airspeed") text: qsTr("Airspeed")
visible: (controller.vehicle.fixedWing || controller.vehicle.vtol) && visible: (controller.vehicle.fixedWing || controller.vehicle.vtol) &&
controller.getParameterFact(-1, "FW_ARSP_MODE").value === false && controller.getParameterFact(-1, "FW_ARSP_MODE").value == 0 &&
controller.getParameterFact(-1, "CBRK_AIRSPD_CHK").value !== 162128 && controller.getParameterFact(-1, "CBRK_AIRSPD_CHK").value !== 162128 &&
QGroundControl.corePlugin.options.showSensorCalibrationAirspeed && QGroundControl.corePlugin.options.showSensorCalibrationAirspeed &&
showSensorCalibrationAirspeed showSensorCalibrationAirspeed
......
...@@ -790,7 +790,7 @@ QGCCameraControl::_loadSettings(const QDomNodeList nodeList) ...@@ -790,7 +790,7 @@ QGCCameraControl::_loadSettings(const QDomNodeList nodeList)
QVariant typedValue; QVariant typedValue;
QString errorString; QString errorString;
if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) { if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) {
metaData->setIncrement(typedValue.toDouble()); metaData->setRawIncrement(typedValue.toDouble());
} else { } else {
qWarning() << "Invalid step value for" << factName qWarning() << "Invalid step value for" << factName
<< " type:" << metaData->type() << " type:" << metaData->type()
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
****************************************************************************/ ****************************************************************************/
#include "Fact.h" #include "Fact.h"
#include "FactValueSliderListModel.h"
#include "QGCMAVLink.h" #include "QGCMAVLink.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "QGCCorePlugin.h" #include "QGCCorePlugin.h"
...@@ -18,13 +19,14 @@ ...@@ -18,13 +19,14 @@
static const char* kMissingMetadata = "Meta data pointer missing"; static const char* kMissingMetadata = "Meta data pointer missing";
Fact::Fact(QObject* parent) Fact::Fact(QObject* parent)
: QObject(parent) : QObject (parent)
, _componentId(-1) , _componentId (-1)
, _rawValue(0) , _rawValue (0)
, _type(FactMetaData::valueTypeInt32) , _type (FactMetaData::valueTypeInt32)
, _metaData(NULL) , _metaData (NULL)
, _sendValueChangedSignals(true) , _sendValueChangedSignals (true)
, _deferredValueChangeSignal(false) , _deferredValueChangeSignal(false)
, _valueSliderModel (NULL)
{ {
FactMetaData* metaData = new FactMetaData(_type, this); FactMetaData* metaData = new FactMetaData(_type, this);
setMetaData(metaData); setMetaData(metaData);
...@@ -34,14 +36,15 @@ Fact::Fact(QObject* parent) ...@@ -34,14 +36,15 @@ Fact::Fact(QObject* parent)
} }
Fact::Fact(int componentId, QString name, FactMetaData::ValueType_t type, QObject* parent) Fact::Fact(int componentId, QString name, FactMetaData::ValueType_t type, QObject* parent)
: QObject(parent) : QObject (parent)
, _name(name) , _name (name)
, _componentId(componentId) , _componentId (componentId)
, _rawValue(0) , _rawValue (0)
, _type(type) , _type (type)
, _metaData(NULL) , _metaData (NULL)
, _sendValueChangedSignals(true) , _sendValueChangedSignals (true)
, _deferredValueChangeSignal(false) , _deferredValueChangeSignal(false)
, _valueSliderModel (NULL)
{ {
FactMetaData* metaData = new FactMetaData(_type, this); FactMetaData* metaData = new FactMetaData(_type, this);
setMetaData(metaData); setMetaData(metaData);
...@@ -57,9 +60,8 @@ Fact::Fact(FactMetaData* metaData, QObject* parent) ...@@ -57,9 +60,8 @@ Fact::Fact(FactMetaData* metaData, QObject* parent)
, _metaData (NULL) , _metaData (NULL)
, _sendValueChangedSignals (true) , _sendValueChangedSignals (true)
, _deferredValueChangeSignal(false) , _deferredValueChangeSignal(false)
, _valueSliderModel (NULL)
{ {
// Allow core plugin a chance to override the default value
qgcApp()->toolbox()->corePlugin()->adjustSettingMetaData(*metaData);
setMetaData(metaData, true /* setDefaultFromMetaData */); setMetaData(metaData, true /* setDefaultFromMetaData */);
} }
...@@ -78,7 +80,7 @@ const Fact& Fact::operator=(const Fact& other) ...@@ -78,7 +80,7 @@ const Fact& Fact::operator=(const Fact& other)
_type = other._type; _type = other._type;
_sendValueChangedSignals = other._sendValueChangedSignals; _sendValueChangedSignals = other._sendValueChangedSignals;
_deferredValueChangeSignal = other._deferredValueChangeSignal; _deferredValueChangeSignal = other._deferredValueChangeSignal;
_valueSliderModel = NULL;
if (_metaData && other._metaData) { if (_metaData && other._metaData) {
*_metaData = *other._metaData; *_metaData = *other._metaData;
} else { } else {
...@@ -633,10 +635,20 @@ QString Fact::enumOrValueString(void) ...@@ -633,10 +635,20 @@ QString Fact::enumOrValueString(void)
return QString(); return QString();
} }
double Fact::increment(void) const double Fact::rawIncrement(void) const
{ {
if (_metaData) { if (_metaData) {
return _metaData->increment(); return _metaData->rawIncrement();
} else {
qWarning() << kMissingMetadata << name();
}
return std::numeric_limits<double>::quiet_NaN();
}
double Fact::cookedIncrement(void) const
{
if (_metaData) {
return _metaData->cookedIncrement();
} else { } else {
qWarning() << kMissingMetadata << name(); qWarning() << kMissingMetadata << name();
} }
...@@ -682,3 +694,11 @@ bool Fact::volatileValue(void) const ...@@ -682,3 +694,11 @@ bool Fact::volatileValue(void) const
return false; return false;
} }
} }
FactValueSliderListModel* Fact::valueSliderModel(void)
{
if (!_valueSliderModel) {
_valueSliderModel = new FactValueSliderListModel(*this);
}
return _valueSliderModel;
}
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
#include <QDebug> #include <QDebug>
#include <QAbstractListModel>
class FactValueSliderListModel;
/// @brief A Fact is used to hold a single value within the system. /// @brief A Fact is used to hold a single value within the system.
class Fact : public QObject class Fact : public QObject
...@@ -66,7 +69,7 @@ public: ...@@ -66,7 +69,7 @@ public:
Q_PROPERTY(bool valueEqualsDefault READ valueEqualsDefault NOTIFY valueChanged) Q_PROPERTY(bool valueEqualsDefault READ valueEqualsDefault NOTIFY valueChanged)
Q_PROPERTY(QString valueString READ cookedValueString NOTIFY valueChanged) Q_PROPERTY(QString valueString READ cookedValueString NOTIFY valueChanged)
Q_PROPERTY(QString enumOrValueString READ enumOrValueString NOTIFY valueChanged) Q_PROPERTY(QString enumOrValueString READ enumOrValueString NOTIFY valueChanged)
Q_PROPERTY(double increment READ increment CONSTANT) Q_PROPERTY(double increment READ cookedIncrement CONSTANT)
Q_PROPERTY(bool typeIsString READ typeIsString CONSTANT) Q_PROPERTY(bool typeIsString READ typeIsString CONSTANT)
Q_PROPERTY(bool typeIsBool READ typeIsBool CONSTANT) Q_PROPERTY(bool typeIsBool READ typeIsBool CONSTANT)
Q_PROPERTY(bool hasControl READ hasControl CONSTANT) Q_PROPERTY(bool hasControl READ hasControl CONSTANT)
...@@ -115,7 +118,8 @@ public: ...@@ -115,7 +118,8 @@ public:
bool valueEqualsDefault (void) const; bool valueEqualsDefault (void) const;
bool rebootRequired (void) const; bool rebootRequired (void) const;
QString enumOrValueString (void); // This is not const, since an unknown value can modify the enum lists QString enumOrValueString (void); // This is not const, since an unknown value can modify the enum lists
double increment (void) const; double rawIncrement (void) const;
double cookedIncrement (void) const;
bool typeIsString (void) const { return type() == FactMetaData::valueTypeString; } bool typeIsString (void) const { return type() == FactMetaData::valueTypeString; }
bool typeIsBool (void) const { return type() == FactMetaData::valueTypeBool; } bool typeIsBool (void) const { return type() == FactMetaData::valueTypeBool; }
bool hasControl (void) const; bool hasControl (void) const;
...@@ -123,6 +127,8 @@ public: ...@@ -123,6 +127,8 @@ public:
bool writeOnly (void) const; bool writeOnly (void) const;
bool volatileValue (void) const; bool volatileValue (void) const;
Q_INVOKABLE FactValueSliderListModel* valueSliderModel(void);
/// Returns the values as a string with full 18 digit precision if float/double. /// Returns the values as a string with full 18 digit precision if float/double.
QString rawValueStringFullPrecision(void) const; QString rawValueStringFullPrecision(void) const;
...@@ -192,6 +198,7 @@ protected: ...@@ -192,6 +198,7 @@ protected:
FactMetaData* _metaData; FactMetaData* _metaData;
bool _sendValueChangedSignals; bool _sendValueChangedSignals;
bool _deferredValueChangeSignal; bool _deferredValueChangeSignal;
FactValueSliderListModel* _valueSliderModel;
}; };
#endif #endif
...@@ -8,14 +8,13 @@ import QGroundControl.Controls 1.0 ...@@ -8,14 +8,13 @@ import QGroundControl.Controls 1.0
QGCCheckBox { QGCCheckBox {
property Fact fact: Fact { } property Fact fact: Fact { }
property variant checkedValue: 1
property variant uncheckedValue: 0
checkedState: fact ? checkedState: fact ?
(fact.typeIsBool ? (fact.typeIsBool ?
(fact.value === false ? Qt.Unchecked : Qt.Checked) : (fact.value === false ? Qt.Unchecked : Qt.Checked) :
(fact.value === 0 ? Qt.Unchecked : Qt.Checked)) : (fact.value === 0 ? Qt.Unchecked : Qt.Checked)) :
Qt.Unchecked Qt.Unchecked
text: qsTr("Label") onClicked: fact.value = (checked ? checkedValue : uncheckedValue)
onClicked: fact.value = checked ? 1 : 0
} }
...@@ -88,6 +88,8 @@ void FactPanelController::_reportMissingParameter(int componentId, const QString ...@@ -88,6 +88,8 @@ void FactPanelController::_reportMissingParameter(int componentId, const QString
QString missingParam = QString("%1:%2").arg(componentId).arg(name); QString missingParam = QString("%1:%2").arg(componentId).arg(name);
qCWarning(FactPanelControllerLog) << "Missing parameter:" << missingParam;
// If missing parameters a reported from the constructor of a derived class we // If missing parameters a reported from the constructor of a derived class we
// will not have access to _factPanel yet. Just record list of missing facts // will not have access to _factPanel yet. Just record list of missing facts
// in that case instead of notify. Once _factPanel is available they will be // in that case instead of notify. Once _factPanel is available they will be
......
...@@ -20,16 +20,11 @@ QGCTextField { ...@@ -20,16 +20,11 @@ QGCTextField {
property string _validateString property string _validateString
// At this point all Facts are numeric
inputMethodHints: ((fact && fact.typeIsString) || ScreenTools.isiOS) ? inputMethodHints: ((fact && fact.typeIsString) || ScreenTools.isiOS) ?
Qt.ImhNone : // iOS numeric keyboard has no done button, we can't use it Qt.ImhNone : // iOS numeric keyboard has no done button, we can't use it
Qt.ImhFormattedNumbersOnly // Forces use of virtual numeric keyboard Qt.ImhFormattedNumbersOnly // Forces use of virtual numeric keyboard
onEditingFinished: { onEditingFinished: {
if (ScreenTools.isMobile) {
// Toss focus on mobile after Done on virtual keyboard. Prevent strange interactions.
focus = false
}
if (typeof qgcView !== 'undefined' && qgcView) { if (typeof qgcView !== 'undefined' && qgcView) {
var errorString = fact.validate(text, false /* convertOnly */) var errorString = fact.validate(text, false /* convertOnly */)
if (errorString === "") { if (errorString === "") {
......
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactSystem 1.0
Rectangle {
height: _itemHeight
width: _totalSlots * _itemWidth
color: qgcPal.textField
property Fact fact: undefined
property int digitCount: 4 ///< The number of digits to show for each value
property int incrementSlots: 1 ///< The number of visible slots to left/right of center value
property int _totalDigitCount: digitCount + 1 + fact.units.length
property real _margins: (ScreenTools.implicitTextFieldHeight - ScreenTools.defaultFontPixelHeight) / 2
property real _increment: fact.increment
property real _value: fact.value
property int _decimalPlaces: fact.decimalPlaces
property string _units: fact.units
property real _prevValue: _value - _increment
property real _nextValue: _value + _increment
property real _itemWidth: (_totalDigitCount * ScreenTools.defaultFontPixelWidth) + (_margins * 2)
property real _itemHeight: ScreenTools.implicitTextFieldHeight
property var _valueModel
property int _totalSlots: (incrementSlots * 2) + 1
property int _currentIndex: _totalSlots / 2
property int _currentRelativeIndex: _currentIndex
property int _prevIncrementSlots: incrementSlots
property int _nextIncrementSlots: incrementSlots
property int _selectionWidth: 3
property var _model: fact.valueSliderModel()
property var _fact: fact
QGCPalette { id: qgcPal; colorGroupEnabled: parent.enabled }
QGCPalette { id: qgcPalDisabled; colorGroupEnabled: false }
function firstVisibleIndex() {
return valueListView.contentX / _itemWidth
}
function recalcRelativeIndex() {
_currentRelativeIndex = _currentIndex - firstVisibleIndex()
_prevIncrementSlots = _currentRelativeIndex
_nextIncrementSlots = _totalSlots - _currentRelativeIndex - 1
}
function reset() {
valueListView.positionViewAtIndex(0, ListView.Beginning)
_currentIndex = _model.resetInitialValue()
valueListView.positionViewAtIndex(_currentIndex, ListView.Center)
recalcRelativeIndex()
}
Component.onCompleted: {
valueListView.maximumFlickVelocity = valueListView.maximumFlickVelocity / 2
reset()
}
Connections {
target: _fact
onValueChanged: reset()
}
Component {
id: editDialogComponent
ParameterEditorDialog {
fact: _fact
}
}
QGCListView {
id: valueListView
anchors.fill: parent
orientation: ListView.Horizontal
snapMode: ListView.SnapToItem
clip: true
model: _model
delegate: QGCLabel {
width: _itemWidth
height: _itemHeight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: value + " " + _units
color: qgcPal.textFieldText
MouseArea {
anchors.fill: parent
onClicked: {
valueListView.focus = true
if (_currentIndex === index) {
qgcView.showDialog(editDialogComponent, qsTr("Value Details"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel)
} else {
_currentIndex = index
valueListView.positionViewAtIndex(_currentIndex, ListView.Center)
recalcRelativeIndex()
fact.value = value
}
}
}
}
onMovementStarted: valueListView.focus = true
onMovementEnded: {
_currentIndex = firstVisibleIndex() + _currentRelativeIndex
fact.value = _model.valueAtModelIndex(_currentIndex)
}
}
Rectangle {
id: leftOverlay
width: _itemWidth * _prevIncrementSlots
height: _itemHeight
color: qgcPal.textField
opacity: 0.5
}
Rectangle {
width: _itemWidth * _nextIncrementSlots
height: _itemHeight
anchors.right: parent.right
color: qgcPal.textField
opacity: 0.5
}
Rectangle {
x: _currentRelativeIndex * _itemWidth - _borderWidth
y: -_borderWidth
width: _itemWidth + (_borderWidth * 2)
height: _itemHeight + (_borderWidth * 2)
border.width: _borderWidth
border.color: qgcPal.brandingBlue
color: "transparent"
readonly property int _borderWidth: 3
}
}
...@@ -8,3 +8,4 @@ FactPanel 1.0 FactPanel.qml ...@@ -8,3 +8,4 @@ FactPanel 1.0 FactPanel.qml
FactTextField 1.0 FactTextField.qml FactTextField 1.0 FactTextField.qml
FactTextFieldGrid 1.0 FactTextFieldGrid.qml FactTextFieldGrid 1.0 FactTextFieldGrid.qml
FactTextFieldRow 1.0 FactTextFieldRow.qml FactTextFieldRow 1.0 FactTextFieldRow.qml
FactValueSlider 1.0 FactValueSlider.qml
...@@ -105,6 +105,7 @@ void FactGroup::_addFact(Fact* fact, const QString& name) ...@@ -105,6 +105,7 @@ void FactGroup::_addFact(Fact* fact, const QString& name)
fact->setMetaData(_nameToFactMetaDataMap[name]); fact->setMetaData(_nameToFactMetaDataMap[name]);
} }
_nameToFactMap[name] = fact; _nameToFactMap[name] = fact;
_factNames.append(name);
} }
void FactGroup::_addFactGroup(FactGroup* factGroup, const QString& name) void FactGroup::_addFactGroup(FactGroup* factGroup, const QString& name)
......
...@@ -38,7 +38,7 @@ public: ...@@ -38,7 +38,7 @@ public:
/// @return FactGroup for specified name, NULL if not found /// @return FactGroup for specified name, NULL if not found
Q_INVOKABLE FactGroup* getFactGroup(const QString& name); Q_INVOKABLE FactGroup* getFactGroup(const QString& name);
QStringList factNames(void) const { return _nameToFactMap.keys(); } QStringList factNames(void) const { return _factNames; }
QStringList factGroupNames(void) const { return _nameToFactGroupMap.keys(); } QStringList factGroupNames(void) const { return _nameToFactGroupMap.keys(); }
protected: protected:
...@@ -59,7 +59,7 @@ protected: ...@@ -59,7 +59,7 @@ protected:
QMap<QString, Fact*> _nameToFactMap; QMap<QString, Fact*> _nameToFactMap;
QMap<QString, FactGroup*> _nameToFactGroupMap; QMap<QString, FactGroup*> _nameToFactGroupMap;
QMap<QString, FactMetaData*> _nameToFactMetaDataMap; QMap<QString, FactMetaData*> _nameToFactMetaDataMap;
QStringList _factNames;
}; };
#endif #endif
This diff is collapsed.
...@@ -111,7 +111,8 @@ public: ...@@ -111,7 +111,8 @@ public:
/// Amount to increment value when used in controls such as spin button or slider with detents. /// Amount to increment value when used in controls such as spin button or slider with detents.
/// NaN for no increment available. /// NaN for no increment available.
double increment (void) const { return _increment; } double rawIncrement (void) const { return _rawIncrement; }
double cookedIncrement (void) const;
Translator rawTranslator (void) const { return _rawTranslator; } Translator rawTranslator (void) const { return _rawTranslator; }
Translator cookedTranslator (void) const { return _cookedTranslator; } Translator cookedTranslator (void) const { return _cookedTranslator; }
...@@ -135,7 +136,7 @@ public: ...@@ -135,7 +136,7 @@ public:
void setShortDescription(const QString& shortDescription) { _shortDescription = shortDescription; } void setShortDescription(const QString& shortDescription) { _shortDescription = shortDescription; }
void setRawUnits (const QString& rawUnits); void setRawUnits (const QString& rawUnits);
void setRebootRequired (bool rebootRequired) { _rebootRequired = rebootRequired; } void setRebootRequired (bool rebootRequired) { _rebootRequired = rebootRequired; }
void setIncrement (double increment) { _increment = increment; } void setRawIncrement (double increment) { _rawIncrement = increment; }
void setHasControl (bool bValue) { _hasControl = bValue; } void setHasControl (bool bValue) { _hasControl = bValue; }
void setReadOnly (bool bValue) { _readOnly = bValue; } void setReadOnly (bool bValue) { _readOnly = bValue; }
void setWriteOnly (bool bValue) { _writeOnly = bValue; } void setWriteOnly (bool bValue) { _writeOnly = bValue; }
...@@ -215,7 +216,7 @@ private: ...@@ -215,7 +216,7 @@ private:
}; };
struct AppSettingsTranslation_s { struct AppSettingsTranslation_s {
const char* rawUnits; QString rawUnits;
const char* cookedUnits; const char* cookedUnits;
UnitTypes unitType; UnitTypes unitType;
uint32_t unitOption; uint32_t unitOption;
...@@ -248,7 +249,7 @@ private: ...@@ -248,7 +249,7 @@ private:
Translator _rawTranslator; Translator _rawTranslator;
Translator _cookedTranslator; Translator _cookedTranslator;
bool _rebootRequired; bool _rebootRequired;
double _increment; double _rawIncrement;
bool _hasControl; bool _hasControl;
bool _readOnly; bool _readOnly;
bool _writeOnly; bool _writeOnly;
...@@ -264,7 +265,7 @@ private: ...@@ -264,7 +265,7 @@ private:
} constants; } constants;
struct BuiltInTranslation_s { struct BuiltInTranslation_s {
const char* rawUnits; QString rawUnits;
const char* cookedUnits; const char* cookedUnits;
Translator rawTranslator; Translator rawTranslator;
Translator cookedTranslator; Translator cookedTranslator;
...@@ -285,6 +286,7 @@ private: ...@@ -285,6 +286,7 @@ private:
static const char* _mobileDefaultValueJsonKey; static const char* _mobileDefaultValueJsonKey;
static const char* _minJsonKey; static const char* _minJsonKey;
static const char* _maxJsonKey; static const char* _maxJsonKey;
static const char* _incrementJsonKey;
static const char* _hasControlJsonKey; static const char* _hasControlJsonKey;
}; };
......
...@@ -20,10 +20,6 @@ ...@@ -20,10 +20,6 @@
/// The components of the FactSystem are a Fact which holds an individual value. FactMetaData holds /// The components of the FactSystem are a Fact which holds an individual value. FactMetaData holds
/// additional meta data associated with a Fact such as description, min/max ranges and so forth. /// additional meta data associated with a Fact such as description, min/max ranges and so forth.
/// The FactValidator object is a QML validator which validates input according to the FactMetaData
/// settings. Client code can then use this system to expose sets of Facts to QML code. An example
/// of this is the PX4ParameterMetaData onbject which is part of the PX4 AutoPilot plugin. It exposes
/// the firmware parameters to QML such that you can bind QML ui elements directly to parameters.
class FactSystem : public QGCTool class FactSystem : public QGCTool
{ {
......
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef FactValidator_H
#define FactValidator_H
#include <QValidator>
class Fact;
/// QML Validator for Facts (Work In Progress)
///
/// The validator uses the FactMetaData to impose restrictions on the input. It is used as follows:
/// @code{.unparsed}
/// TextInput {
/// validator: FactValidator { fact: parameters["RC_MAP_THROTTLE"]; }
/// }
/// @endcode
class FactValidator : public QValidator
{
Q_OBJECT
Q_PROPERTY(Fact* fact READ fact WRITE setFact)
public:
FactValidator(QObject* parent = NULL);
// Property system methods
/// Read accessor for fact property
Fact* fact(void) { return _fact; }
/// Write accessor for fact property
void setFact(Fact* fact) { _fact = fact; }
/// Override from QValidator
virtual void fixup(QString& input) const;
/// Override from QValidator
virtual State validate(QString& input, int& pos) const;
private:
Fact* _fact; ///< Fact that the validator is working on
};
#endif
\ No newline at end of file
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "FactValueSliderListModel.h"
#include <QDebug>
#include <QQmlEngine>
#include <QtMath>
#include <math.h>
const int FactValueSliderListModel::_valueRole = Qt::UserRole;
const int FactValueSliderListModel::_valueIndexRole = Qt::UserRole + 1;
FactValueSliderListModel::FactValueSliderListModel(Fact& fact, QObject* parent)
: QAbstractListModel (parent)
, _fact (fact)
, _cValues (0)
, _firstValueIndexInWindow (0)
, _initialValueIndex (0)
, _cPrevValues (0)
, _cNextValues (0)
, _initialValue (0)
, _initialValueRounded (0)
, _increment (0)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
}
FactValueSliderListModel::~FactValueSliderListModel()
{
}
int FactValueSliderListModel::resetInitialValue(void)
{
if (_cValues > 0) {
// Remove any old rows
beginRemoveRows(QModelIndex(), 0, _cValues - 1);
_cValues = 0;
endRemoveRows();
}
_initialValue = _fact.cookedValue().toDouble();
_initialValueRounded = qRound(_initialValue);
if (qRound(_fact.rawIncrement()) == _fact.rawIncrement()) {
_increment = qRound(_fact.cookedIncrement());
} else {
_increment = _fact.cookedIncrement();
}
_cPrevValues = qMin((_initialValue - _fact.cookedMin().toDouble()), 1000.0) / _increment;
_cNextValues = qMin((_fact.cookedMax().toDouble() - _initialValue), 1000.0) / _increment;
_initialValueIndex = _cPrevValues;
int totalValueCount = _cPrevValues + 1 + _cNextValues;
beginInsertRows(QModelIndex(), 0, totalValueCount - 1);
_cValues = totalValueCount;
endInsertRows();
return _initialValueIndex;
}
int FactValueSliderListModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return _cValues;
}
QVariant FactValueSliderListModel::data(const QModelIndex &index, int role) const
{
Q_UNUSED(role);
if (!index.isValid()) {
return QVariant();
}
int valueIndex = index.row();
if (valueIndex >= _cValues) {
return QVariant();
}
if (role == _valueRole) {
double value;
int cIncrementCount = valueIndex - _initialValueIndex;
if (cIncrementCount == 0) {
value = _initialValue;
} else {
value = _initialValueRounded + (cIncrementCount * _increment);
}
double precision = qPow(10, _fact.decimalPlaces());
double atPrecision = qRound(value * precision) / precision;
//qDebug() << value << precision << atPrecision << _fact.decimalPlaces() << _fact.name();
return QVariant(atPrecision);
} else if (role == _valueIndexRole) {
return QVariant::fromValue(valueIndex);
} else {
return QVariant();
}
}
QHash<int, QByteArray> FactValueSliderListModel::roleNames(void) const
{
QHash<int, QByteArray> hash;
hash[_valueRole] = "value";
hash[_valueIndexRole] = "valueIndex";
return hash;
}
double FactValueSliderListModel::valueAtModelIndex(int index)
{
return data(createIndex(index, 0), _valueRole).toDouble();
}
int FactValueSliderListModel::valueIndexAtModelIndex(int index)
{
return data(createIndex(index, 0), _valueIndexRole).toInt();
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include <QAbstractListModel>
#include "Fact.h"
/// Provides a list model of values for incrementing/decrementing the value of a Fact
class FactValueSliderListModel : public QAbstractListModel
{
Q_OBJECT
public:
FactValueSliderListModel(Fact& fact, QObject* parent = NULL);
~FactValueSliderListModel();
Q_INVOKABLE int resetInitialValue(void);
Q_INVOKABLE double valueAtModelIndex(int index);
Q_INVOKABLE int valueIndexAtModelIndex(int index);
private:
// Overrides from QAbstractListModel
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames(void) const override;
Fact& _fact;
int _cValues;
int _firstValueIndexInWindow;
int _initialValueIndex;
int _cPrevValues;
int _cNextValues;
int _windowSize;
double _initialValue;
double _initialValueRounded;
double _increment;
static const int _valueRole;
static const int _valueIndexRole;
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment