diff --git a/.github/workflows/build_package_Rock5.yml b/.github/workflows/build_package_Rock5.yml
index fc5f7c812..203479dc4 100644
--- a/.github/workflows/build_package_Rock5.yml
+++ b/.github/workflows/build_package_Rock5.yml
@@ -2,9 +2,9 @@ name: build_package_rock5_debian
on:
push:
- branches: [ "2.4-evo" ]
+ branches: [ "2.5-evo" ]
pull_request:
- branches: [ "2.4-evo" ]
+ branches: [ "2.5-evo" ]
jobs:
build:
@@ -36,7 +36,7 @@ jobs:
- name: Build Package
run: |
git clone https://github.com/OpenHD/ChrootCompilationTest /opt/ChrootCompilationTest
- git clone -b 2.4-evo https://github.com/OpenHD/QOpenHD --recursive /opt/ChrootCompilationTest/additionalFiles
+ git clone -b 2.5-evo https://github.com/OpenHD/QOpenHD --recursive /opt/ChrootCompilationTest/additionalFiles
echo $CLOUDSMITH_API_KEY > /opt/ChrootCompilationTest/additionalFiles/cloudsmith_api_key.txt
cd /opt/ChrootCompilationTest/
sudo apt update
diff --git a/.github/workflows/build_package_rpi.yml b/.github/workflows/build_package_rpi.yml
index 2f30859ce..7655dd880 100644
--- a/.github/workflows/build_package_rpi.yml
+++ b/.github/workflows/build_package_rpi.yml
@@ -2,9 +2,9 @@ name: build_package_rpi
on:
push:
- branches: [ "2.4-evo" ]
+ branches: [ "2.5-evo" ]
pull_request:
- branches: [ "2.4-evo" ]
+ branches: [ "2.5-evo" ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
diff --git a/.github/workflows/build_package_x86_jammy.yml b/.github/workflows/build_package_x86_jammy.yml
index 9fa74a550..03d9adf54 100644
--- a/.github/workflows/build_package_x86_jammy.yml
+++ b/.github/workflows/build_package_x86_jammy.yml
@@ -2,9 +2,9 @@ name: build_package_x86_22
on:
push:
- branches: [ "2.4-evo" ]
+ branches: [ "2.5-evo" ]
pull_request:
- branches: [ "2.4-evo" ]
+ branches: [ "2.5-evo" ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
@@ -33,21 +33,10 @@ jobs:
sudo rm -rf /var/lib/apt/lists/*
sudo apt upgrade -y
sudo add-apt-repository universe
- sudo ./install_build_dep.sh ubuntu-x86 custom
-
-
-
+ sudo ./install_build_dep.sh ubuntu-x86
- name: Build with make
run: |
- sudo rm -f /etc/ld.so.conf.d/qt.conf
- sudo touch /etc/ld.so.conf.d/qt.conf
- sudo sh -c 'echo "/opt/Qt5.15.7/lib/" >/etc/ld.so.conf.d/qt.conf'
- sudo ldconfig
- export PATH="$PATH:/opt/Qt5.15.7/bin/"
- sudo rm -f /usr/bin/qmake
- sudo ln -s /opt/Qt5.15.7/bin/qmake /usr/bin/qmake
- echo "QT successfully linked"
sudo ./package.sh x86_64 ubuntu jammy
- name: Push
diff --git a/.github/workflows/build_package_x86_usb_release.yml b/.github/workflows/build_package_x86_usb_release.yml
index 762af45ee..06694e6a0 100644
--- a/.github/workflows/build_package_x86_usb_release.yml
+++ b/.github/workflows/build_package_x86_usb_release.yml
@@ -1,4 +1,4 @@
-name: build_package_x86_23.04
+name: build_package_LUNAR
on:
push:
diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml
new file mode 100644
index 000000000..82a4337db
--- /dev/null
+++ b/.github/workflows/build_windows.yml
@@ -0,0 +1,125 @@
+name: Windows Release
+
+on: [push]
+
+defaults:
+ run:
+ shell: cmd
+
+env:
+ SOURCE_DIR: ${{ github.workspace }}
+ ARTIFACT: QOpenHD-Evo.zip
+
+jobs:
+ build:
+ runs-on: windows-2019
+
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v3
+ with:
+ submodules: recursive
+
+ - name: Install Qt
+ uses: jurplel/install-qt-action@v3
+ with:
+ aqtversion: '==2.1.*'
+ version: '5.15.2'
+ host: 'windows'
+ target: 'desktop'
+ arch: 'win64_msvc2019_64'
+ tools: 'tools_ifw tools_qtcreator,qt.tools.qtcreator'
+ setup-python: false
+
+ - name: Download JOM
+ uses: suisei-cn/actions-download-file@v1
+ with:
+ url: http://download.qt.io/official_releases/jom/jom.zip
+
+ - name: Unzip JOM
+ run: |
+ 7z x jom.zip -ojom
+
+ - uses: ilammy/msvc-dev-cmd@v1
+ - name: Build
+ run: |
+ ls D:\a\QOpenHD\Qt\5.15.2\msvc2019_64\bin\
+ rm -rf build
+ mkdir build
+ cd build
+ qmake CONFIG+=release ..\QOpenHD.pro
+ ..\jom\jom -j2
+ ls -a
+ cd release
+ cd
+ cd D:\a\QOpenHD\Qt\5.15.2\msvc2019_64\bin\
+ cp *.dll D:\a\QOpenHD\QOpenHD\build\release\
+ cd D:\a\QOpenHD\QOpenHD\build\release\
+ mkdir platforms
+ cd D:\a\QOpenHD\Qt\5.15.2\msvc2019_64\plugins\platforms\
+ cp *.dll D:\a\QOpenHD\QOpenHD\build\release\platforms\
+ cd D:\a\QOpenHD\Qt\5.15.2\msvc2019_64\qml\
+ cp -r * D:\a\QOpenHD\QOpenHD\build\release\
+ cd D:\a\QOpenHD\QOpenHD\build\release\
+ rm -Rf Qt3D
+ rm -Rf QtBluetooth
+ rm -Rf QtDataVisualization
+ rm -Rf QtGamepad
+ rm -Rf QtNfc
+ rm -Rf QtPurchasing
+ rm -Rf QtQuick3D
+ rm -Rf QtRemoteObjects
+ rm -Rf QtScxml
+ rm -Rf QtSensors
+ rm -Rf QtWebChannel
+ rm -Rf QtWebEngine
+ rm -Rf QtWebSockets
+ rm -Rf QtWebView
+ rm -Rf QtWinExtras
+ rm Qt5Bluetooth.dll
+ rm Qt5Bluetoothd.dll
+ rm QtGamepad.dll
+ rm QtGamepadd.dll
+ rm QtWebChannel.dll
+ rm QtWebChanneld.dll
+ rm Qt5WebSockets.dll
+ rm Qt5WebSocketsd.dll
+ rm Qt5WebView.dll
+ rm Qt5WebViewd.dll
+ rm Qt53DAnimation.dll
+ rm Qt53DAnimationd.dll
+ rm Qt53DACore.dll
+ rm Qt53DACored.dll
+ rm Qt53DExtras.dll
+ rm Qt53DExtrasd.dll
+ rm Qt53DInput.dll
+ rm Qt53DInputd.dll
+ rm Qt53DLogic.dll
+ rm Qt53DLogicd.dll
+ rm Qt53DQuick.dll
+ rm Qt53DQuickd.dll
+ rm Qt53DQuickAnimation.dll
+ rm Qt53DQuickAnimationd.dll
+ rm Qt53DQuickExtras.dll
+ rm Qt53DQuickExtrasd.dll
+ rm Qt53DQuickInput.dll
+ rm Qt53DQuickInputd.dll
+ rm Qt53DQuickRender.dll
+ rm Qt53DQuickRenderd.dll
+ rm Qt53DQuickScene2D.dll
+ rm Qt53DQuickScene2Dd.dll
+ rm Qt53DRender.dll
+ rm Qt53DRenderd.dll
+ ls -a
+ cd
+
+ - name: Upload to Github
+ uses: 'actions/upload-artifact@v2'
+ with:
+ name: "QOpenHD"
+ path: |
+ D:\a\QOpenHD\QOpenHD\build\release\
+
+
+
+
diff --git a/.github/workflows/ios.yml.txt b/.github/workflows/ios.yml.txt
index 5d74e4fee..6075fce5d 100644
--- a/.github/workflows/ios.yml.txt
+++ b/.github/workflows/ios.yml.txt
@@ -29,8 +29,7 @@ jobs:
- name: Install Dependencies
run: |
-
- sudo ./build_install_mavsdk_static.sh
+ # TODO ?
- name: Build with make
run: |
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
new file mode 100644
index 000000000..1f0f94ca9
--- /dev/null
+++ b/.github/workflows/macos.yml
@@ -0,0 +1,41 @@
+name: Build MacOS
+
+on:
+ push:
+
+env:
+ # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
+ BUILD_TYPE: Release
+
+jobs:
+ build:
+ runs-on: macos-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Checkout repo
+ uses: actions/checkout@v3
+ with:
+ submodules: recursive
+
+
+ - name: Install Qt
+ uses: jurplel/install-qt-action@v3
+
+ # - name: Install create-dmg
+ # run: brew install create-dmg
+
+
+ - name: Build
+ # Build your program with the given configuration
+ run: |
+ qmake CONFIG+=release QOpenHD.pro
+
+
+ - name: Upload to Github
+ uses: 'actions/upload-artifact@v3'
+ with:
+ name: "OpenHD Image Writer"
+ path: |
+ *.app
diff --git a/.github/workflows/ubuntu22_build_test.yml b/.github/workflows/ubuntu22_build_test.yml
index 53203d109..2eafcc0ec 100644
--- a/.github/workflows/ubuntu22_build_test.yml
+++ b/.github/workflows/ubuntu22_build_test.yml
@@ -30,7 +30,7 @@ jobs:
sudo apt upgrade -y
sudo apt remove libunwind-13-dev
sudo apt install -y libunwind-dev libgstreamer-plugins-base1.0-dev
- sudo ./install_build_dep.sh ubuntu-x86 custom
+ sudo ./install_build_dep.sh ubuntu-x86
qmake --version
- name: Build with make
run: |
diff --git a/.gitmodules b/.gitmodules
index a2e313452..794b06e4a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,7 +1,4 @@
-[submodule "lib/MAVSDK"]
- path = lib/MAVSDK
- url = https://github.com/OpenHD/MAVSDK.git
-[submodule "lib/mavsdk_prebuilts"]
- path = lib/mavsdk_prebuilts
- url = https://github.com/OpenHD/mavsdk_prebuilts.git
+[submodule "lib/mavlink-headers"]
+ path = lib/mavlink-headers
+ url = https://github.com/OpenHD/mavlink-headers.git
diff --git a/LICENSE b/LICENSE
index 53d1f3d01..a59201f91 100644
--- a/LICENSE
+++ b/LICENSE
@@ -232,6 +232,10 @@ terms of section 4, provided that you also meet all of these conditions:
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
+ e) The "Credits" section of this App is subject to the following terms in addition to the GNU General Public License (GPL) version 3:
+ The content presented in the "Credits" section of this App is considered a copyrighted declaration. Unauthorized modifications, suppression, or removal of this content are strictly prohibited without explicit consent from the OpenHD development team.
+
+
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
diff --git a/QOpenHD.pro b/QOpenHD.pro
index f3f0afc4e..c245d9714 100755
--- a/QOpenHD.pro
+++ b/QOpenHD.pro
@@ -68,7 +68,6 @@ LinuxBuild {
# (aka all these really should come with pretty much any qt install)
# In general, parts of QOpenHD that need additional libraries should have their code in a subdirectory with a .pri where those
# dependencies are added such that you can easily compile the project even on systems that might lack some of those qt functionalities
-# see app/adsb/adsb_lib.pri for an example
QT +=core quick qml gui \
widgets
QT += opengl
@@ -77,7 +76,7 @@ INCLUDEPATH += $$PWD/lib
INCLUDEPATH += $$PWD/app
INCLUDEPATH += $$PWD/app/exp
-# QOpenHD telemetry (mavlink, partially based on MAVSDK) features
+# QOpenHD telemetry (mavlink)
# REQUIRED - without it QOpenHD will compile, but be pretty much non functional
include(app/telemetry/telemetry.pri)
@@ -99,12 +98,6 @@ LinuxBuild {
include(app/videostreaming/gstreamer/gst_video.pri)
}
-# adsb library
-# Only tested on linux so far, but might work on other platforms already / with minimal effort, too
-LinuxBuild {
- include(app/adsb/adsb_lib.pri)
-}
-
# All Generic files / files that literally have 0!! dependencies other than qt
SOURCES += \
app/logging/hudlogmessagesmodel.cpp \
@@ -139,7 +132,6 @@ SOURCES += \
app/osd/horizonladder.cpp \
app/osd/speedladder.cpp \
app/osd/altitudeladder.cpp \
- app/osd/drawingcanvas.cpp \
app/osd/flightpathvector.cpp \
app/osd/aoagauge.cpp \
app/osd/performancehorizonladder.cpp \
@@ -149,7 +141,6 @@ HEADERS += \
app/osd/horizonladder.h \
app/osd/speedladder.h \
app/osd/altitudeladder.h \
- app/osd/drawingcanvas.h \
app/osd/flightpathvector.h \
app/osd/debug_overdraw.hpp \
app/osd/aoagauge.h \
@@ -182,15 +173,7 @@ DISTFILES += \
android/src/org/freedesktop/gstreamer/androidmedia/GstAmcOnFrameAvailableListener.java \
android/src/org/openhd/IsConnected.java \
android/src/org/openhd/LiveVideoPlayerWrapper.java \
- app/adsb/adsb_lib.pri \
- app/logging/README.txt \
- app/openhd_systems/README.md \
- app/osd_extra/Readme.txt \
- app/platform/README.md \
app/telemetry/telemetry.pri \
- app/util/README.md \
- app/videostreaming/README.md \
- app/videostreaming/README.txt \
app/videostreaming/gst_qmlglsink/gst_video.pri \
app/videostreaming/vscommon/vscommon.pri \
app/vs_android/videostreamingandroid.pri \
@@ -248,7 +231,7 @@ JetsonBuild {
}
WindowsBuild {
- # This aparently makes qt use absolute paths, otherwise we get problems with mavsdk
+ # This aparently makes qt use absolute paths, otherwise we get compile issues ?
QMAKE_PROJECT_DEPTH = 0
}
diff --git a/README.md b/README.md
index a75f6ba02..05465c24d 100644
--- a/README.md
+++ b/README.md
@@ -2,131 +2,93 @@
QOpenHD is the default OpenHD companion app that runs on the OHD Ground station or any other "external" devices connected to the ground station.
-It is responsible for displaying the (main) video stream to the user, composed with the OSD and changing OpenHD settings.
+It is responsible for displaying the main video stream to the user, composed with the OSD, and changing OpenHD settings.
-As the name suspects, it is based on QT (5.15.X) and will not run on older Versions.
+As the name suggests, it is based on QT (5.15.X) and will not run on older versions.
-![temporary_screenshot](wiki/temporary_screenshot.png)
+![temporary_screenshot](https://1945119839-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8RIMU39m4Gt1vqzzt4lm%2Fuploads%2Fgit-blob-353dff94866ae2d4a81fa3329bf93290a0271b42%2FNorbertScreenshot.png?alt=media)
-# Developer Design Overview (incomplete)
-1) QOpenHD is not OpenHD (main). It can talk to a running OpenHD main instance (ground and/or air) via Mavlink and rceives the (primary / secondary / ++) video streams.
-2) While QOpenHD is the default companion app, OpenHD MUST NOT assume there is a QOpenHD instance somewhere that initiates voodo settings / setup processes
-( This is in contrast to OpenHD /QOpenHD releases before the "evo" series.) As a result of this limitation, Both OpenHD and QOpenHD can be developed independently from each other, and debugging becomes a lot easier.
+## Developer Design Overview (incomplete)
-# Compiling:
-We have a CI setup that checks compilation on ubuntu. You can look at the steps it performs to build and run QOpenHD.
-Other platforms than Linux are not supported right now.
+1. QOpenHD is not OpenHD (main). It can communicate with a running OpenHD main instance (ground and/or air) via Mavlink and receives the (primary / secondary / ++) video streams.
+2. While QOpenHD is the default companion app, OpenHD MUST NOT assume there is a QOpenHD instance somewhere that initiates voodoo settings / setup processes. This is in contrast to OpenHD/QOpenHD releases before the "evo" series. As a result of this limitation, both OpenHD and QOpenHD can be developed independently from each other, making debugging easier.
-# Building QOpenHD Locally in QT (GSTREAMER MIGHT NOT BE REQUIRED as things progress)
-#### Mac
-
-1. Install Xcode from the Mac App Store.
-
-2. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer)
-
-3. Have the Qt Installer download Qt 5.15.0+ for Mac, and Qt Creator
+## Installing
-4. Clone the source code:
+Like every OpenHD app or module, we publish packages into our [Cloudsmith Repository](https://cloudsmith.io/~openhd/repos/openhd-2-3-evo/). There are Packages for X86 (ubuntu 22.04,23.04), armhf (rpi, arm64 rockchip). Android releases are available on the Playstore and can be downloaded from there.
- git clone --recurse-submodules https://github.com/OpenHD/QOpenHD.git
+## Compiling
-If you aren't using git from the command line but using a GUI git client instead, make sure
-you update the submodules or QOpenHD will not build properly.
-
+We have a CI setup that checks compilation on Ubuntu. You can review the steps it performs to build and run QOpenHD. Other platforms than Linux are not supported at the moment.
-Once you have those steps done you can open `QOpenHD.pro` with Qt Creator, build and run it.
+### Building QOpenHD Locally in QT (CURRENTLY UNDER DEVELOPMENT)
-#### iOS
+#### Mac
1. Install Xcode from the Mac App Store.
+2. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer).
+3. Download Qt 5.15.0+ for Mac and Qt Creator using the Qt Installer.
+4. Clone the source code:
-2. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer)
-
-3. Have the Qt Installer download Qt 5.15.0+ for iOS, and Qt Creator
-
-4. You will need an Apple developer membership to install directly to an iOS device
-
-5. Clone the source code:
-
+ ```
git clone --recurse-submodules https://github.com/OpenHD/QOpenHD.git
+ ```
-If you aren't using git from the command line but using a GUI git client instead, make sure
-you update the submodules or QOpenHD will not build properly.
-
-Once you have those steps done you can open `QOpenHD.pro` with Qt Creator, build and run it.
-
-#### Windows
-
-1. Install Visual Studio 2019 (free)
-
-2. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer)
-
-3. Have the Qt Installer download Qt 5.15.0+ and Qt Creator
-
-4. Download the [GStreamer development kit](https://gstreamer.freedesktop.org/download/) for Windows, both the Runtime and Development packages. You *must use* the 32-bit MinGW packages, NOT the one labeled MSVC, and it should be version 1.14.4. (QT will look for gstreamer in c:/gstreamer/1.0/x86 )
+ If you use a GUI git client, ensure you update the submodules or QOpenHD won't build properly.
-5. Clone the source code:
+#### iOS
- git clone --recurse-submodules https://github.com/OpenHD/QOpenHD.git
+1. Install Xcode from the Mac App Store.
+2. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer).
+3. Download Qt 5.15.0+ for iOS and Qt Creator using the Qt Installer.
+4. You'll need an Apple developer membership to install directly on an iOS device.
+5. Clone the source code as mentioned earlier.
-If you aren't using git from the command line but using a GUI git client instead, make sure
-you update the submodules or QOpenHD will not build properly.
+#### Windows (CURRENTLY UNDER DEVELOPMENT)
-Once you have those steps done you can open `QOpenHD.pro` with Qt Creator, build and run it.
+1. Install Visual Studio 2019 (free).
+2. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer).
+3. Download Qt 5.15.0+ and Qt Creator using the Qt Installer.
+4. Download the [GStreamer development kit](https://gstreamer.freedesktop.org/download/) for Windows, both the Runtime and Development packages (32-bit MinGW packages, version 1.14.4). QT will look for gstreamer in c:/gstreamer/1.0/x86.
+5. Clone the source code as mentioned earlier.
#### Linux
-1. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer)
-
-2. Have it download Qt 5.15.0+ for Linux
-
-3. Install GStreamer development packages from the package manager. On Ubuntu this would be `apt install gstreamer1.0-gl libgstreamer1.0-dev libgstreamer-plugins-good1.0-dev gstreamer1.0-plugins-good libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-base libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-qt`. Those should pull in any others that are needed as well.
+**QTCreator**
-4. Clone the source code:
-
- git clone --recurse-submodules https://github.com/OpenHD/QOpenHD.git
+1. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer).
+2. Have it download Qt 5.15.0+ for Linux.
+3. Install GStreamer development packages from the package manager (e.g., on Ubuntu, run `apt install gstreamer1.0-gl libgstreamer1.0-dev libgstreamer-plugins-good1.0-dev gstreamer1.0-plugins-good libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-base libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-qt`).
+4. Clone the source code as mentioned earlier.
-If you aren't using git from the command line but using a GUI git client instead, make sure
-you update the submodules or QOpenHD will not build properly.
+### Manual via qmake
-Once you have those steps done you can open `QOpenHD.pro` with Qt Creator, build and run it.
+1. Clone the source code.
+2. Run 'bash install_build_dependencies.sh ARCHITECTURE' (ARCHITECTURE can be X86, rpi, rock5).
+3. Run 'build_qmake.sh'.
+4. Find the binary under build/releases/QOpenHD.
#### Android
-1. Install [Android Studio](https://developer.android.com/studio)
-
-2. Use Android Studio to install Android SDK level 28, along with NDK r18b and the associated build toolchain.
-
-3. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer)
-
-4. Have the Qt Installer download Qt 5.15.0+ *for Android*, not for the OS you're building on.
-
-5. Clone the source code:
-
- git clone --recurse-submodules https://github.com/OpenHD/QOpenHD.git
-
-If you aren't using git from the command line but using a GUI git client instead, make sure
-you update the submodules or QOpenHD will not build properly.
-
-You can then open `QOpenHD.pro` using Qt Creator and set up the Android kit (left side, click the Projects tab), build and run the app on your device.
-
-
-
-# Building MAVSDK (REQUIRED)
-QOpenHD relies on MAVSDK library. After recursively cloning qopenhd you have to build and install it once:
-
-`./build_install_mavsdk_static.sh`
+1. Install [Android Studio](https://developer.android.com/studio).
+2. Install Android SDK level 28 and NDK r18b using Android Studio.
+3. Install Qt using the [Qt online installer](https://www.qt.io/download-qt-installer).
+4. Download Qt 5.15.0+ for Android (not for the OS you're building on).
+5. Clone the source code as mentioned earlier.
-After that, you can build QOpenHD by either opening it in QT Creator (recommended) or building it with the following commands:
+### Building QOpenHD
-`mkdir build`
-`cd build`
-`qmake ..`
+Step 1) clone this repository with --recurse-submodules
+Step 2) install all dependencies
+Step 3) recommended - open in QT creator. Otherwise, you can build QOpenHD via the command line:
+```
+mkdir build
+cd build
+qmake ..
+```
-# Contributing
+## Contributing
-**Thanks to all the people who already contributed!**
+**Thanks to all the people who have contributed!**
-
-
-
+![Contributors](https://fra1.digitaloceanspaces.com/openhd-images/uploads/QOpenHD.svg)
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 0d6c20c6d..f4a2a3979 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -1,6 +1,6 @@
-
+
@@ -106,6 +106,8 @@
+
+
diff --git a/app/adsb/ADSBVehicle.cpp b/app/adsb/ADSBVehicle.cpp
deleted file mode 100644
index 40b643dcf..000000000
--- a/app/adsb/ADSBVehicle.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
- *
- * This file has been ported from QGroundControl project
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#include "ADSBVehicle.h"
-
-#include
-#include
-
-ADSBVehicle::ADSBVehicle(const VehicleInfo_t& vehicleInfo, QObject* parent)
- : QObject (parent)
- , _icaoAddress (vehicleInfo.icaoAddress)
- , _altitude (qQNaN())
- , _heading (qQNaN())
- , _alert (false)
-{
- update(vehicleInfo);
-}
-
-void ADSBVehicle::update(const VehicleInfo_t& vehicleInfo)
-{
- if (_icaoAddress != vehicleInfo.icaoAddress) {
- qDebug() << "ICAO address mismatch expected:actual" << _icaoAddress << vehicleInfo.icaoAddress;
- return;
- }
- if (vehicleInfo.availableFlags & CallsignAvailable) {
- if (vehicleInfo.callsign != _callsign) {
- _callsign = vehicleInfo.callsign;
- emit callsignChanged();
- }
- }
- if (vehicleInfo.availableFlags & LocationAvailable) {
- if (_coordinate != vehicleInfo.location) {
- _coordinate = vehicleInfo.location;
- emit coordinateChanged();
- }
- }
- if (vehicleInfo.availableFlags & AltitudeAvailable) {
- if (!(qIsNaN(vehicleInfo.altitude) && qIsNaN(_altitude)) && !qFuzzyCompare(vehicleInfo.altitude, _altitude)) {
- _altitude = vehicleInfo.altitude;
- emit altitudeChanged();
- }
- }
- if (vehicleInfo.availableFlags & HeadingAvailable) {
- if (!(qIsNaN(vehicleInfo.heading) && qIsNaN(_heading)) && !qFuzzyCompare(vehicleInfo.heading, _heading)) {
- _heading = vehicleInfo.heading;
- emit headingChanged();
- }
- }
- if (vehicleInfo.availableFlags & AlertAvailable) {
- if (vehicleInfo.alert != _alert) {
- _alert = vehicleInfo.alert;
- emit alertChanged();
- }
- }
- if (vehicleInfo.availableFlags & VelocityAvailable) {
- if (vehicleInfo.velocity != _velocity) {
- _velocity = vehicleInfo.velocity;
- emit velocityChanged();
- }
- }
- if (vehicleInfo.availableFlags & VerticalVelAvailable) {
- if (vehicleInfo.verticalVel != _verticalVel) {
- _verticalVel = vehicleInfo.verticalVel;
- emit verticalVelChanged();
- }
- }
- if (vehicleInfo.availableFlags & LastContactAvailable) {
- if (vehicleInfo.lastContact != _lastContact) {
- _lastContact = vehicleInfo.lastContact;
- emit lastContactChanged();
- }
- }
- if (vehicleInfo.availableFlags & DistanceAvailable) {
- if (vehicleInfo.distance != _distance) {
- _distance = vehicleInfo.distance;
- emit distanceChanged();
- }
- }
- _lastUpdateTimer.restart();
-}
-
-bool ADSBVehicle::expired()
-{
- return _lastUpdateTimer.hasExpired(expirationTimeoutMs);
-}
-
-bool ADSBVehicle::tooFar()
-{
- return _too_far;
-}
diff --git a/app/adsb/ADSBVehicle.h b/app/adsb/ADSBVehicle.h
deleted file mode 100644
index 6a3acbc64..000000000
--- a/app/adsb/ADSBVehicle.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************************
- *
- * This file has been ported from QGroundControl project
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#pragma once
-
-#include
-#include
-#include
-
-class ADSBVehicle : public QObject
-{
- Q_OBJECT
-
-public:
- enum {
- CallsignAvailable = 1 << 1,
- LocationAvailable = 1 << 2,
- AltitudeAvailable = 1 << 3,
- HeadingAvailable = 1 << 4,
- AlertAvailable = 1 << 5,
- VelocityAvailable = 1 << 6,
- VerticalVelAvailable = 1 << 7,
- LastContactAvailable = 1 << 8,
- DistanceAvailable = 1 << 8
- };
-
- typedef struct {
- uint32_t icaoAddress; // Required
- QString callsign;
- QGeoCoordinate location;
- double altitude;
- double velocity;
- double heading;
- int alert;
- uint32_t availableFlags;
- int lastContact;
- double verticalVel;
- double distance;
- } VehicleInfo_t;
-
- ADSBVehicle(const VehicleInfo_t& vehicleInfo, QObject* parent);
-
- Q_PROPERTY(int icaoAddress READ icaoAddress CONSTANT)
- Q_PROPERTY(QString callsign READ callsign NOTIFY callsignChanged)
- Q_PROPERTY(QGeoCoordinate coordinate READ coordinate NOTIFY coordinateChanged)
- Q_PROPERTY(double lat READ lat NOTIFY coordinateChanged)
- Q_PROPERTY(double lon READ lon NOTIFY coordinateChanged)
- Q_PROPERTY(double altitude READ altitude NOTIFY altitudeChanged) // NaN for not available
- Q_PROPERTY(double velocity READ velocity NOTIFY velocityChanged) // NaN for not available
- Q_PROPERTY(double heading READ heading NOTIFY headingChanged) // NaN for not available
- Q_PROPERTY(int alert READ alert NOTIFY alertChanged) // Collision path
- Q_PROPERTY(int lastContact READ lastContact NOTIFY lastContactChanged)
- Q_PROPERTY(double verticalVel READ verticalVel NOTIFY verticalVelChanged)
- Q_PROPERTY(double distance READ distance NOTIFY distanceChanged)
-
- int icaoAddress (void) const { return static_cast(_icaoAddress); }
- QString callsign (void) const { return _callsign; }
- QGeoCoordinate coordinate (void) const { return _coordinate; }
- double lat (void) const { return _coordinate.latitude(); }
- double lon (void) const { return _coordinate.longitude(); }
- double altitude (void) const { return _altitude; }
- double velocity (void) const { return _velocity; }
- double heading (void) const { return _heading; }
- int alert (void) const { return _alert; }
- int lastContact (void) const { return _lastContact; }
- double verticalVel (void) const { return _verticalVel; }
- double distance (void) const { return _distance; }
-
- void update(const VehicleInfo_t& vehicleInfo);
-
- /// check if the vehicle is expired and should be removed
- bool expired();
-
- bool tooFar();
-
-signals:
- void coordinateChanged ();
- void callsignChanged ();
- void altitudeChanged ();
- void velocityChanged ();
- void headingChanged ();
- void alertChanged ();
- void lastContactChanged ();
- void verticalVelChanged ();
- void distanceChanged ();
-
-private:
- // This is the time in ms our vehicle will expire and thus removed from map
- static constexpr qint64 expirationTimeoutMs = 25000;
-
- uint32_t _icaoAddress;
- QString _callsign;
- QGeoCoordinate _coordinate;
- double _altitude;
- double _velocity;
- double _heading;
- int _alert;
- int _lastContact;
- double _verticalVel;
- double _distance;
-
- QElapsedTimer _lastUpdateTimer;
-
- bool _too_far = false;
-};
-
-Q_DECLARE_METATYPE(ADSBVehicle::VehicleInfo_t)
-
diff --git a/app/adsb/ADSBVehicleManager.cpp b/app/adsb/ADSBVehicleManager.cpp
deleted file mode 100644
index 68b48b8cb..000000000
--- a/app/adsb/ADSBVehicleManager.cpp
+++ /dev/null
@@ -1,615 +0,0 @@
-/****************************************************************************
- *
- * (c) 2009-2020 QGROUNDCONTROL PROJECT
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#include "ADSBVehicleManager.h"
-//#include "localmessage.h"
-//#include "logger.h"
-#include "../telemetry/models/fcmavlinksystem.h"
-#include "qmath.h"
-
-#include
-
-static ADSBVehicleManager* _instance = nullptr;
-
-ADSBVehicleManager* ADSBVehicleManager::instance()
-{
- if ( _instance == nullptr ) {
- _instance = new ADSBVehicleManager();
- }
- return _instance;
-}
-
-ADSBVehicleManager::ADSBVehicleManager(QObject *parent) : QObject(parent)
-{
-}
-
-ADSBVehicleManager::~ADSBVehicleManager()
-{
- // manually stop the threads
- _internetLink->quit();
- _internetLink->wait();
-
- _sdrLink->quit();
- _sdrLink->wait();
-}
-
-void ADSBVehicleManager::onStarted()
-{
-// MavlinkTelemetry* mavlinktelemetry = MavlinkTelemetry::instance();
-// connect(mavlinktelemetry, &MavlinkTelemetry::adsbVehicleUpdate, this, &ADSBVehicleManager::adsbVehicleUpdate, Qt::QueuedConnection);
-
- qDebug() << "ADSBVehicleManager::onStarted()";
-
- connect(&_adsbVehicleCleanupTimer, &QTimer::timeout, this, &ADSBVehicleManager::_cleanupStaleVehicles);
- _adsbVehicleCleanupTimer.setSingleShot(false);
- _adsbVehicleCleanupTimer.start(4500);
-
- _internetLink = new ADSBInternet();
- connect(_internetLink, &ADSBInternet::adsbVehicleUpdate, this, &ADSBVehicleManager::adsbVehicleUpdate, Qt::QueuedConnection);
- connect(this, &ADSBVehicleManager::mapCenterChanged, _internetLink, &ADSBInternet::mapBoundsChanged, Qt::QueuedConnection);
- connect(_internetLink, &ADSBInternet::adsbClearModelRequest, this, &ADSBVehicleManager::adsbClearModel, Qt::QueuedConnection);
-
- _sdrLink = new ADSBSdr();
- connect(_sdrLink, &ADSBSdr::adsbVehicleUpdate, this, &ADSBVehicleManager::adsbVehicleUpdate, Qt::QueuedConnection);
- connect(this, &ADSBVehicleManager::mapCenterChanged, _sdrLink, &ADSBSdr::mapBoundsChanged, Qt::QueuedConnection);
- connect(_sdrLink, &ADSBSdr::adsbClearModelRequest, this, &ADSBVehicleManager::adsbClearModel, Qt::QueuedConnection);
-}
-
-// called from qml when the map is moved
-void ADSBVehicleManager::newMapCenter(QGeoCoordinate center_coord) {
- //qDebug() << "ADSBVehicleManager::newMapCenter";
- _api_center_coord = center_coord;
- emit mapCenterChanged(center_coord);
-}
-
-void ADSBVehicleManager::_cleanupStaleVehicles()
-{
- // Remove all expired ADSB vehicles
- for (int i=_adsbVehicles.count()-1; i>=0; i--) {
- ADSBVehicle* adsbVehicle = _adsbVehicles.value(i);
- if (adsbVehicle->expired()) {
- // qDebug() << "Expired" << QStringLiteral("%1").arg(adsbVehicle->icaoAddress(), 0, 16);
- _adsbVehicles.removeAt(i);
- _adsbICAOMap.remove(adsbVehicle->icaoAddress());
- adsbVehicle->deleteLater();
- }
- }
- // if more than 20 seconds with with no updates, set frontend indicator red
- // if more than 60 seconds with no updates deactivate frontend indicator
- if (_last_update_timer.elapsed() > 60000) {
- _status = 0;
- emit statusChanged();
-
- } else if (_last_update_timer.elapsed() > 20000) {
- _status = 1;
- emit statusChanged();
- }
-}
-
-//currently not used.. was for testing but could have future purpose to turn off display
-void ADSBVehicleManager::adsbClearModel(){
- //qDebug() << "_adsbVehicles.clearAndDeleteContents";
- _adsbVehicles.clearAndDeleteContents();
-}
-
-void ADSBVehicleManager::adsbVehicleUpdate(const ADSBVehicle::VehicleInfo_t vehicleInfo)
-{
- //qDebug() << "ADSBVehicleManager::adsbVehicleUpdate";
- uint32_t icaoAddress = vehicleInfo.icaoAddress;
-
- //no point in continuing because no location. This is somewhat redundant with parser
- //possible situation where we start to not get location.. and gets stale then removed
- if (vehicleInfo.availableFlags & ADSBVehicle::LocationAvailable) {
-
- //decide if its new or needs update
- if (_adsbICAOMap.contains(icaoAddress)) {
- _adsbICAOMap[icaoAddress]->update(vehicleInfo);
- }
- else {
-
- ADSBVehicle* adsbVehicle = new ADSBVehicle(vehicleInfo, this);
- _adsbICAOMap[icaoAddress] = adsbVehicle;
- //qDebug() << "ADSBVehicleManager::adsbVehicleUpdate append vehicle";
- _adsbVehicles.append(adsbVehicle);
- }
-
- // Show warnings if adsb reported traffic is too close
- _evaluateTraffic(vehicleInfo.altitude, vehicleInfo.distance);
-
- _last_update_timer.restart();
- _status = 2;
- emit statusChanged();
- }
-}
-
-void ADSBVehicleManager::_evaluateTraffic(double traffic_alt, int traffic_distance)
-{
- /*
- * Centralise traffic threat detection here. Once threat is detected it should be
- * labled and then sent over to the adsb widget
- *
- * need to calculate azimuth and bearing of any threats so that it can be shared
- * and depicted in the adsb widget
- */
- int drone_alt = FCMavlinkSystem::instance().altitude_msl_m();
-
- if (traffic_alt - drone_alt < 300 && traffic_distance < 2) {
-// LocalMessage::instance()->showMessage("Aircraft Traffic", 3);
-
- } else if (traffic_alt - drone_alt < 500 && traffic_distance < 5) {
-// LocalMessage::instance()->showMessage("Aircraft Traffic", 4);
- }
-}
-
-ADSBapi::ADSBapi()
- : QThread()
-{
- moveToThread(this);
- start();
-}
-
-ADSBapi::~ADSBapi(void)
-{
- quit();
- wait();
-}
-
-void ADSBapi::run(void)
-{
- init();
- exec();
-}
-
-void ADSBapi::init(void) {
- qDebug() << "------------------>Adsbapi::init()<------------------------";
-
- QNetworkAccessManager * manager = new QNetworkAccessManager(this);
-
- m_manager = manager;
-
- connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(processReply(QNetworkReply*))) ;
-
- timer = new QTimer(this);
- connect(timer, &QTimer::timeout, this, &ADSBapi::requestData);
-
- // How frequently data is requested
- timer->start(timer_interval);
- mapBoundsChanged(QGeoCoordinate(40.48205, -3.35996));
-}
-
-
-void ADSBapi::mapBoundsChanged(QGeoCoordinate center_coord) {
- _api_center_coord= center_coord;
-
- //qDebug() << "ADSBapi::mapBoundsChanged center cord:" << _api_center_coord;
-
- qreal adsb_distance_limit = _settings.value("adsb_distance_limit").toInt();
-
- QGeoCoordinate qgeo_upper_left;
- QGeoCoordinate qgeo_lower_right;
-
- qgeo_upper_left = center_coord.atDistanceAndAzimuth(adsb_distance_limit, 315, 0.0);
- qgeo_lower_right = center_coord.atDistanceAndAzimuth(adsb_distance_limit, 135, 0.0);
-
- upperl_lat= QString::number(qgeo_upper_left.latitude());
- upperl_lon= QString::number(qgeo_upper_left.longitude());
- lowerr_lat= QString::number(qgeo_lower_right.latitude());
- lowerr_lon= QString::number(qgeo_lower_right.longitude());
-}
-
-void ADSBInternet::requestData(void) {
- // If openskynetwork is disabled by settings don't make the request and return
- if (!_adsb_api_openskynetwork || !_show_adsb_internet) {
- return;
- }
- qDebug() << "------------------>ADSBInternet::requestData<------------------------";
- _adsb_api_openskynetwork = _settings.value("adsb_api_openskynetwork").toBool();
- _show_adsb_internet = _settings.value("show_adsb").toBool();
-
-
-
- adsb_url= "https://opensky-network.org/api/states/all?lamin="+lowerr_lat+"&lomin="+upperl_lon+"&lamax="+upperl_lat+"&lomax="+lowerr_lon;
-
- QNetworkRequest request;
- QUrl api_request = adsb_url;
- request.setUrl(api_request);
- request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
-
- qDebug() << "url=" << api_request;
- m_manager->get(request);
-}
-
-void ADSBInternet::processReply(QNetworkReply *reply) {
- qDebug() << "------------------>ADSBInternet::processReply<------------------------";
-
-
- if (!_adsb_api_openskynetwork || !_show_adsb_internet) {
- qDebug() << "------------------>ADSBInternet::processReply EARLY RETURN <------------------------";
-
- return;
- }
-
- max_distance=(_settings.value("adsb_distance_limit").toInt())/1000;
- unknown_zero_alt=_settings.value("adsb_show_unknown_or_zero_alt").toBool();
-
- //qDebug() << "MAX adsb distance=" << max_distance;
-
- if (reply->error()) {
- qDebug() << "ADSB OpenSky request error!";
- qDebug() << reply->errorString();
-// LocalMessage::instance()->showMessage("ADSB OpenSky Reply Error", 4);
- reply->deleteLater();
- return;
- }
-
- QJsonParseError errorPtr;
- QByteArray data = reply->readAll();
- QJsonDocument doc = QJsonDocument::fromJson(data, &errorPtr);
-
- if (doc.isNull()) {
- qDebug() << "ADSB Opensky network response: Parse failed";
-// LocalMessage::instance()->showMessage("ADSB OpenSky Parse Error", 4);
- reply->deleteLater();
- return;
- }
-
- if(!doc.isObject()){
- qDebug()<<"JSON is not an object.";
- reply->deleteLater();
- return;
- }
-
- QJsonObject jsonObject = doc.object();
-
- if(jsonObject.isEmpty()){
- qDebug()<<"ADSB Openskynetwork response: JSON object is empty.";
-// LocalMessage::instance()->showMessage("ADSB OpenSky empty object", 4);
- reply->deleteLater();
- return;
- }
-
- QJsonValue value = jsonObject.value("states");
- QJsonArray array = value.toArray();
-
- foreach (const QJsonValue & v, array){
-
- ADSBVehicle::VehicleInfo_t adsbInfo;
- bool icaoOk;
-
- QJsonArray innerarray = v.toArray();
- QString icaoAux = innerarray[0].toString();
- adsbInfo.icaoAddress = icaoAux.toUInt(&icaoOk, 16);
-
- // Skip this element if icao number is not ok
- if (!icaoOk) {
- continue;
- }
-
- // location comes in lat lon format, but we need it as QGeoCoordinate
- if(innerarray[6].isNull() || innerarray[5].isNull()){ //skip if no lat lon
- continue;
- }
- double lat = innerarray[6].toDouble();
- double lon = innerarray[5].toDouble();
- QGeoCoordinate location(lat, lon);
- adsbInfo.location = location;
- adsbInfo.availableFlags |= ADSBVehicle::LocationAvailable;
-
- //evaluate distance for INTERNET adsb traffic... this is redundant with sdr
- double lat_1 = _api_center_coord.latitude();
- double lon_1 = _api_center_coord.longitude();
-
- double latDistance = qDegreesToRadians(lat_1 - lat);
- double lngDistance = qDegreesToRadians(lon_1 - lon);
-
- double a = qSin(latDistance / 2) * qSin(latDistance / 2)
- + qCos(qDegreesToRadians(lat_1)) * qCos(qDegreesToRadians(lat))
- * qSin(lngDistance / 2) * qSin(lngDistance / 2);
-
- double c = 2 * qAtan2(qSqrt(a), qSqrt(1 - a));
- double distance = 6371 * c;
-
- adsbInfo.distance = distance;
- //qDebug() << "adsb internet distance=" << distance;
- adsbInfo.availableFlags |= ADSBVehicle::DistanceAvailable;
-
- // If aircraft beyond max distance than skip this one
- if(distance>max_distance){
- qDebug() << "Beyond max SKIPPING";
- continue;
- }
-
- // rest of fields
-
- // callsign
- adsbInfo.callsign = innerarray[1].toString();
- if (adsbInfo.callsign.length() == 0) {
- adsbInfo.callsign = "N/A";
- }
- adsbInfo.availableFlags |= ADSBVehicle::CallsignAvailable;
-
- //altitude
- if(innerarray[7].isDouble()){
- adsbInfo.altitude = innerarray[7].toDouble();
- //per setting eliminate all unknown alt
- if (adsbInfo.altitude<5 && unknown_zero_alt==false){
- //skip this traffic
- continue;
- }
- }
- else {
- //per setting eliminate all unknown alt
- if (unknown_zero_alt==false){
- //skip this traffic
- continue;
- }
- else {
- adsbInfo.altitude=99999.9;
- }
- }
- adsbInfo.availableFlags |= ADSBVehicle::AltitudeAvailable;
-
- //velocity
- if(innerarray[9].isDouble()){
- adsbInfo.velocity = innerarray[9].toDouble() * 3.6; // m/s to km/h
- }
- else {
- adsbInfo.velocity=99999.9;
- }
- adsbInfo.availableFlags |= ADSBVehicle::VelocityAvailable;
-
- //heading
- if(innerarray[10].isDouble()){
- adsbInfo.heading = innerarray[10].toDouble();
- }
- else {
- adsbInfo.heading=0.0;
- }
- adsbInfo.availableFlags |= ADSBVehicle::HeadingAvailable;
-
- //last contact
- if(innerarray[4].isNull()){
- adsbInfo.lastContact=0;
- }
- else {
- adsbInfo.lastContact = innerarray[4].toInt();
- }
- adsbInfo.availableFlags |= ADSBVehicle::LastContactAvailable;
-
- //vertical velocity
- if(innerarray[11].isDouble()){
- adsbInfo.verticalVel = innerarray[11].toDouble();
- }
- else {
- adsbInfo.verticalVel=0.0;
- }
- adsbInfo.availableFlags |= ADSBVehicle::VerticalVelAvailable;
-
- // this is received on adsbvehicleupdate slot
- emit adsbVehicleUpdate(adsbInfo);
- }
- reply->deleteLater();
-}
-
-ADSBSdr::ADSBSdr()
- : ADSBapi()
-{
- // we need to manage this properly
- #if defined(__rasp_pi__)
- _groundAddress = "127.0.0.1";
- #endif
-
- timer_interval = 2000;
-}
-
-void ADSBSdr::requestData(void) {
-// Logger::instance()->logData("request data", 1);
- _adsb_api_sdr = _settings.value("adsb_api_sdr").toBool();
- _show_adsb_sdr = _settings.value("show_adsb").toBool();
-
- // If sdr is disabled by settings don't make the request and return
- if (!_adsb_api_sdr || !_show_adsb_sdr) {
- return;
- }
-
- adsb_url= "http://"+_groundAddress+":8080/data/aircraft.json";
-
- QNetworkRequest request;
- QUrl api_request = adsb_url;
- request.setUrl(api_request);
- request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
-
- // qDebug() << "url=" << api_request;
- m_manager->get(request);
-}
-
-void ADSBSdr::processReply(QNetworkReply *reply) {
-// Logger::instance()->logData("process reply", 1);
- if (!_adsb_api_sdr || !_show_adsb_sdr) {
- return;
- }
-
- max_distance=(_settings.value("adsb_distance_limit").toInt())/1000;
- unknown_zero_alt=_settings.value("adsb_show_unknown_or_zero_alt").toBool();
-
- //qDebug() << "MAX adsb distance=" << max_distance;
-
- if (reply->error()) {
- qDebug() << "ADSB SDR request error!";
- qDebug() << reply->errorString();
-// LocalMessage::instance()->showMessage("ADSB SDR Reply Error", 4);
- reply->deleteLater();
- return;
- }
-
- QJsonParseError errorPtr;
- QByteArray data = reply->readAll();
- QJsonDocument doc = QJsonDocument::fromJson(data, &errorPtr);
-
- if (doc.isNull()) {
- qDebug() << "ADSB SDR response: Parse failed";
-// LocalMessage::instance()->showMessage("ADSB SDR Parse Error", 4);
- reply->deleteLater();
- return;
- }
-
- if(!doc.isObject()){
- qDebug()<<"JSON is not an object.";
- // LocalMessage::instance()->showMessage("ADSB SDR Json not an object", 4);
- reply->deleteLater();
- return;
- }
-
- QJsonObject jsonObject = doc.object();
-
- if(jsonObject.isEmpty()){
- qDebug()<<"ADSB Openskynetwork response: JSON object is empty.";
-// LocalMessage::instance()->showMessage("ADSB SDR Json empty", 4);
- reply->deleteLater();
- return;
- }
-
- QJsonArray array = jsonObject["aircraft"].toArray();
-
- if(array.isEmpty()){
- qDebug()<<"JSON array is empty.";
-// LocalMessage::instance()->showMessage("ADSB SDR Json array empty", 4);
- reply->deleteLater();
- return;
- }
-
- foreach (const QJsonValue & val, array){
-// Logger::instance()->logData("For Each Loop... /n", 1);
- ADSBVehicle::VehicleInfo_t adsbInfo;
- bool icaoOk;
-
- // TODO
- // According to dump1090-mutability, this value can start
- // by "~" in case it isn't a valid ICAO. How this will
- // behave then?
- QString icaoAux = val.toObject().value("hex").toString();
-// Logger::instance()->logData("icaoAux:"+icaoAux, 1);
- adsbInfo.icaoAddress = icaoAux.toUInt(&icaoOk, 16);
-
- // Only continue if icao number is ok
- if (icaoOk) {
-// Logger::instance()->logData("icao ok!", 1);
-
- // location comes in lat lon format, but we need it as QGeoCoordinate
-
- if(val.toObject().value("lat").isNull() || val.toObject().value("lon").isNull()){ //skip if no lat lon
- continue;
- }
-
- double lat = val.toObject().value("lat").toDouble();
- double lon = val.toObject().value("lon").toDouble();
-
- QGeoCoordinate location(lat, lon);
- adsbInfo.location = location;
- adsbInfo.availableFlags |= ADSBVehicle::LocationAvailable;
-
- //evaluate distance for SDR adsb traffic... this is redundant with internet
- double lat_1 = _api_center_coord.latitude();
- double lon_1 = _api_center_coord.longitude();
-
- double latDistance = qDegreesToRadians(lat_1 - lat);
- double lngDistance = qDegreesToRadians(lon_1 - lon);
-
- double a = qSin(latDistance / 2) * qSin(latDistance / 2)
- + qCos(qDegreesToRadians(lat_1)) * qCos(qDegreesToRadians(lat))
- * qSin(lngDistance / 2) * qSin(lngDistance / 2);
-
- double c = 2 * qAtan2(qSqrt(a), qSqrt(1 - a));
- double distance = 6371 * c;
-
- adsbInfo.distance = distance;
- adsbInfo.availableFlags |= ADSBVehicle::DistanceAvailable;
-
- // If aircraft beyond max distance than skip this one
- if(distance>max_distance){
- //qDebug() << "Beyond max SKIPPING";
- continue;
- }
-
- // callsign
- adsbInfo.callsign = val.toObject().value("flight").toString();
-
- if (adsbInfo.callsign.length() == 0) {
- adsbInfo.callsign = "N/A";
- } else {
- adsbInfo.availableFlags |= ADSBVehicle::CallsignAvailable;
- }
-
- //altitude
- if(val.toObject().value("altitude").isNull()){
- //per setting eliminate unknown alt traffic
- if (unknown_zero_alt==false){
- //skip this traffic
- continue;
- } else {
- adsbInfo.altitude=99999.9;
- }
- }
- else {
- adsbInfo.altitude = val.toObject().value("altitude").toInt() * 0.3048;//feet to meters
- //per setting eliminate all unknown alt
- if (adsbInfo.altitude<5 && unknown_zero_alt==false){
- //skip this traffic
- continue;
- }
- }
- adsbInfo.availableFlags |= ADSBVehicle::AltitudeAvailable;
-
- //velocity
- if(val.toObject().value("speed").isNull()){
- adsbInfo.velocity=99999.9;
- }
- else {
- adsbInfo.velocity = round(val.toObject().value("speed").toDouble() * 1.852); // knots to km/h
- }
- adsbInfo.availableFlags |= ADSBVehicle::VelocityAvailable;
-
- //heading
- if(val.toObject().value("track").isNull()){
- adsbInfo.heading=0.0;
- }
- else {
- adsbInfo.heading = val.toObject().value("track").toDouble();
- }
- adsbInfo.availableFlags |= ADSBVehicle::HeadingAvailable;
-
- //last contact
- if(val.toObject().value("seen_pos").isNull()){
- adsbInfo.lastContact=0;
- }
- else {
- adsbInfo.lastContact = val.toObject().value("seen_pos").toInt();
- }
- adsbInfo.availableFlags |= ADSBVehicle::LastContactAvailable;
-
- //vertical velocity
- if(val.toObject().value("vert_rate").isNull()){
- adsbInfo.verticalVel=0.0;
- }
- else {
- adsbInfo.verticalVel = round(val.toObject().value("vert_rate").toDouble() * 0.00508); //feet/min to m/s
- }
- adsbInfo.availableFlags |= ADSBVehicle::VerticalVelAvailable;
-
-
- // this is received on adsbvehicleupdate slot
- emit adsbVehicleUpdate(adsbInfo);
- }
- else {
-// Logger::instance()->logData("icao REJECTED! /n", 1);
- qDebug()<<"ICAO number NOT OK!";
- }
- }
- reply->deleteLater();
-}
diff --git a/app/adsb/ADSBVehicleManager.h b/app/adsb/ADSBVehicleManager.h
deleted file mode 100644
index 0f865f5c8..000000000
--- a/app/adsb/ADSBVehicleManager.h
+++ /dev/null
@@ -1,163 +0,0 @@
-#pragma once
-
-#include "QmlObjectListModel.h"
-#include "ADSBVehicle.h"
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-
-// This is a base clase for inheriting the links for
-// SDR and Opensky network apis
-class ADSBapi : public QThread
-{
- Q_OBJECT
-
-public:
- ADSBapi();
- ~ADSBapi();
-
-signals:
- void adsbVehicleUpdate(const ADSBVehicle::VehicleInfo_t vehicleInfo);
-
- void adsbClearModelRequest();
-
-protected:
- void run(void) final;
-
-public slots:
- void mapBoundsChanged(QGeoCoordinate center_coord);
-
-protected slots:
- virtual void processReply(QNetworkReply *reply) = 0;
- virtual void requestData() = 0;
-
-protected:
- void init();
-
- // network
- QNetworkAccessManager * m_manager;
- QString adsb_url;
-
- // boundingbox parameters
- QString upperl_lat;
- QString upperl_lon;
- QString lowerr_lat;
- QString lowerr_lon;
-
- // timer for requests
- int timer_interval;
- QTimer *timer;
-
- QSettings _settings;
-
- QGeoCoordinate _api_center_coord; //private but duplicated across classes
-
- qreal max_distance;
- bool unknown_zero_alt;
-};
-
-// This class gets the info from Openskynetwork api
-class ADSBInternet: public ADSBapi {
- Q_OBJECT
-
-public:
- ADSBInternet() { timer_interval = 10000; }
- ~ADSBInternet() {}
-
-private slots:
- void processReply(QNetworkReply *reply) override;
- void requestData() override;
-
-private:
- bool _adsb_api_openskynetwork;
- bool _show_adsb_internet; //wired to show widget setting. somewhat redundant
-};
-
-// This class gets the info from SDR
-class ADSBSdr: public ADSBapi {
- Q_OBJECT
-
-public:
- ADSBSdr();
- ~ADSBSdr() {}
-
- void setGroundIP(QString address) { _groundAddress = address; }
-
-private slots:
- void processReply(QNetworkReply *reply) override;
- void requestData() override;
-
-private:
- QString _groundAddress = "";
- bool _adsb_api_sdr;
- bool _show_adsb_sdr; //wired to show widget setting. somewhat redundant
-
-};
-
-class ADSBVehicleManager : public QObject {
- Q_OBJECT
-
-public:
- ADSBVehicleManager(QObject* parent = nullptr);
- ~ADSBVehicleManager();
- static ADSBVehicleManager* instance();
-
- Q_PROPERTY(QmlObjectListModel* adsbVehicles READ adsbVehicles CONSTANT)
- Q_PROPERTY(QGeoCoordinate apiMapCenter READ apiMapCenter MEMBER _api_center_coord NOTIFY mapCenterChanged)
-
- // frontend indicator. 0 inactive, 1 red, 2 green
- Q_PROPERTY(uint status READ status NOTIFY statusChanged)
-
- QmlObjectListModel* adsbVehicles(void) { return &_adsbVehicles; }
- QGeoCoordinate apiMapCenter(void) { return _api_center_coord; }
- uint status() { return _status; }
-
- // called from qml when the map has moved
- Q_INVOKABLE void newMapCenter(QGeoCoordinate center_coord);
-
- Q_INVOKABLE void setGroundIP(QString address) { _sdrLink->setGroundIP(address); }
-
-signals:
- // sent to ADSBapi to make requests based into this
- void mapCenterChanged(QGeoCoordinate center_coord);
-
- // sent to adsbwidgetform.ui to update the status indicator
- void statusChanged(void);
-
-public slots:
- void adsbVehicleUpdate (const ADSBVehicle::VehicleInfo_t vehicleInfo);
- void onStarted();
- void adsbClearModel();
-
-private slots:
- void _cleanupStaleVehicles(void);
-
-private:
- void _evaluateTraffic(double traffic_alt, int traffic_distance);
-
- QmlObjectListModel _adsbVehicles;
- QMap _adsbICAOMap;
- QTimer _adsbVehicleCleanupTimer;
- ADSBInternet* _internetLink = nullptr;
- ADSBSdr* _sdrLink = nullptr;
- QGeoCoordinate _api_center_coord;
- QElapsedTimer _last_update_timer;
- uint _status = 0;
-
- qreal distance = 0;
- QSettings _settings;
-};
diff --git a/app/adsb/QmlObjectListModel.cpp b/app/adsb/QmlObjectListModel.cpp
deleted file mode 100644
index 16dbff9ba..000000000
--- a/app/adsb/QmlObjectListModel.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/****************************************************************************
- *
- * This file has been ported from QGroundControl project
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#include "QmlObjectListModel.h"
-
-#include
-#include
-
-const int QmlObjectListModel::ObjectRole = Qt::UserRole;
-const int QmlObjectListModel::TextRole = Qt::UserRole + 1;
-
-QmlObjectListModel::QmlObjectListModel(QObject* parent)
- : QAbstractListModel (parent)
- , _dirty (false)
- , _skipDirtyFirstItem (false)
- , _externalBeginResetModel (false)
-{
-
-}
-
-QmlObjectListModel::~QmlObjectListModel()
-{
-
-}
-
-QObject* QmlObjectListModel::get(int index)
-{
- if (index < 0 || index >= _objectList.count()) {
- return nullptr;
- }
- return _objectList[index];
-}
-
-int QmlObjectListModel::rowCount(const QModelIndex& parent) const
-{
- Q_UNUSED(parent);
-
- return _objectList.count();
-}
-
-QVariant QmlObjectListModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- if (index.row() < 0 || index.row() >= _objectList.count()) {
- return QVariant();
- }
-
- if (role == ObjectRole) {
- return QVariant::fromValue(_objectList[index.row()]);
- } else if (role == TextRole) {
- return QVariant::fromValue(_objectList[index.row()]->objectName());
- } else {
- return QVariant();
- }
-}
-
-QHash QmlObjectListModel::roleNames(void) const
-{
- QHash hash;
-
- hash[ObjectRole] = "object";
- hash[TextRole] = "text";
-
- return hash;
-}
-
-bool QmlObjectListModel::setData(const QModelIndex& index, const QVariant& value, int role)
-{
- if (index.isValid() && role == ObjectRole) {
- _objectList.replace(index.row(), value.value());
- emit dataChanged(index, index);
- return true;
- }
-
- return false;
-}
-
-bool QmlObjectListModel::insertRows(int position, int rows, const QModelIndex& parent)
-{
- Q_UNUSED(parent);
-
- if (position < 0 || position > _objectList.count() + 1) {
- qWarning() << "Invalid position position:count" << position << _objectList.count();
- }
-
- beginInsertRows(QModelIndex(), position, position + rows - 1);
- endInsertRows();
-
- emit countChanged(count());
-
- return true;
-}
-
-bool QmlObjectListModel::removeRows(int position, int rows, const QModelIndex& parent)
-{
- Q_UNUSED(parent);
-
- if (position < 0 || position >= _objectList.count()) {
- qWarning() << "Invalid position position:count" << position << _objectList.count();
- } else if (position + rows > _objectList.count()) {
- qWarning() << "Invalid rows position:rows:count" << position << rows << _objectList.count();
- }
-
- beginRemoveRows(QModelIndex(), position, position + rows - 1);
- for (int row=0; row= _objectList.count()) {
- return nullptr;
- }
- return _objectList[index];
-}
-
-const QObject* QmlObjectListModel::operator[](int index) const
-{
- if (index < 0 || index >= _objectList.count()) {
- return nullptr;
- }
- return _objectList[index];
-}
-
-void QmlObjectListModel::clear()
-{
- if (!_externalBeginResetModel) {
- beginResetModel();
- }
- _objectList.clear();
- if (!_externalBeginResetModel) {
- endResetModel();
- emit countChanged(count());
- }
-}
-
-QObject* QmlObjectListModel::removeAt(int i)
-{
- QObject* removedObject = _objectList[i];
- if(removedObject) {
- // Look for a dirtyChanged signal on the object
- if (_objectList[i]->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) {
- if (!_skipDirtyFirstItem || i != 0) {
- QObject::disconnect(_objectList[i], SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool)));
- }
- }
- }
- removeRows(i, 1);
- setDirty(true);
- return removedObject;
-}
-
-void QmlObjectListModel::insert(int i, QObject* object)
-{
- if (i < 0 || i > _objectList.count()) {
- qWarning() << "Invalid index index:count" << i << _objectList.count();
- }
- if(object) {
- QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
- // Look for a dirtyChanged signal on the object
- if (object->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) {
- if (!_skipDirtyFirstItem || i != 0) {
- QObject::connect(object, SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool)));
- }
- }
- }
- _objectList.insert(i, object);
- insertRows(i, 1);
- setDirty(true);
-}
-
-void QmlObjectListModel::insert(int i, QList objects)
-{
- if (i < 0 || i > _objectList.count()) {
- qWarning() << "Invalid index index:count" << i << _objectList.count();
- }
-
- int j = i;
- for (QObject* object: objects) {
- QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
-
- // Look for a dirtyChanged signal on the object
- if (object->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("dirtyChanged(bool)")) != -1) {
- if (!_skipDirtyFirstItem || j != 0) {
- QObject::connect(object, SIGNAL(dirtyChanged(bool)), this, SLOT(_childDirtyChanged(bool)));
- }
- }
- j++;
-
- _objectList.insert(j, object);
- }
-
- insertRows(i, objects.count());
-
- setDirty(true);
-}
-
-void QmlObjectListModel::append(QObject* object)
-{
- insert(_objectList.count(), object);
-}
-
-void QmlObjectListModel::append(QList objects)
-{
- insert(_objectList.count(), objects);
-}
-
-QObjectList QmlObjectListModel::swapObjectList(const QObjectList& newlist)
-{
- QObjectList oldlist(_objectList);
- if (!_externalBeginResetModel) {
- beginResetModel();
- }
- _objectList = newlist;
- if (!_externalBeginResetModel) {
- endResetModel();
- emit countChanged(count());
- }
- return oldlist;
-}
-
-int QmlObjectListModel::count() const
-{
- return rowCount();
-}
-
-void QmlObjectListModel::setDirty(bool dirty)
-{
- if (_dirty != dirty) {
- _dirty = dirty;
- if (!dirty) {
- // Need to clear dirty from all children
- for(QObject* object: _objectList) {
- if (object->property("dirty").isValid()) {
- object->setProperty("dirty", false);
- }
- }
- }
- emit dirtyChanged(_dirty);
- }
-}
-
-void QmlObjectListModel::_childDirtyChanged(bool dirty)
-{
- _dirty |= dirty;
- // We want to emit dirtyChanged even if the actual value of _dirty didn't change. It can be a useful
- // signal to know when a child has changed dirty state
- emit dirtyChanged(_dirty);
-}
-
-void QmlObjectListModel::deleteListAndContents()
-{
- for (int i=0; i<_objectList.count(); i++) {
- _objectList[i]->deleteLater();
- }
- deleteLater();
-}
-
-void QmlObjectListModel::clearAndDeleteContents()
-{
- beginResetModel();
- for (int i=0; i<_objectList.count(); i++) {
- _objectList[i]->deleteLater();
- }
- clear();
- endResetModel();
-}
-
-void QmlObjectListModel::beginReset()
-{
- if (_externalBeginResetModel) {
- qWarning() << "QmlObjectListModel::beginReset already set";
- }
- _externalBeginResetModel = true;
- beginResetModel();
-}
-
-void QmlObjectListModel::endReset()
-{
- if (!_externalBeginResetModel) {
- qWarning() << "QmlObjectListModel::endReset begin not set";
- }
- _externalBeginResetModel = false;
- endResetModel();
-}
diff --git a/app/adsb/QmlObjectListModel.h b/app/adsb/QmlObjectListModel.h
deleted file mode 100644
index f99b524f3..000000000
--- a/app/adsb/QmlObjectListModel.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
- *
- * This file has been ported from QGroundControl project
- *
- * QGroundControl is licensed according to the terms in the file
- * COPYING.md in the root of the source code directory.
- *
- ****************************************************************************/
-
-#pragma once
-
-#include
-
-class QmlObjectListModel : public QAbstractListModel
-{
- Q_OBJECT
-
-public:
- QmlObjectListModel(QObject* parent = nullptr);
- ~QmlObjectListModel() override;
-
- Q_PROPERTY(int count READ count NOTIFY countChanged)
-
- /// Returns true if any of the items in the list are dirty. Requires each object to have
- /// a dirty property and dirtyChanged signal.
- Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
-
- Q_INVOKABLE QObject* get(int index);
-
- // Property accessors
-
- int count () const;
- bool dirty () const { return _dirty; }
-
- void setDirty (bool dirty);
- void append (QObject* object);
- void append (QList objects);
- QObjectList swapObjectList (const QObjectList& newlist);
- void clear ();
- QObject* removeAt (int i);
- QObject* removeOne (QObject* object) { return removeAt(indexOf(object)); }
- void insert (int i, QObject* object);
- void insert (int i, QList objects);
- bool contains (QObject* object) { return _objectList.indexOf(object) != -1; }
- int indexOf (QObject* object) { return _objectList.indexOf(object); }
-
- QObject* operator[] (int i);
- const QObject* operator[] (int i) const;
- template T value (int index) { return qobject_cast(_objectList[index]); }
- QList* objectList () { return &_objectList; }
-
- /// Calls deleteLater on all items and this itself.
- void deleteListAndContents ();
-
- /// Clears the list and calls deleteLater on each entry
- void clearAndDeleteContents ();
-
- void beginReset ();
- void endReset ();
-
-signals:
- void countChanged (int count);
- void dirtyChanged (bool dirtyChanged);
-
-private slots:
- void _childDirtyChanged (bool dirty);
-
-private:
- // Overrides from QAbstractListModel
- int rowCount (const QModelIndex & parent = QModelIndex()) const override;
- QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const override;
- bool insertRows (int position, int rows, const QModelIndex &index = QModelIndex()) override;
- bool removeRows (int position, int rows, const QModelIndex &index = QModelIndex()) override;
- bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- QHash roleNames(void) const override;
-
-private:
- QList _objectList;
-
- bool _dirty;
- bool _skipDirtyFirstItem;
- bool _externalBeginResetModel;
-
- static const int ObjectRole;
- static const int TextRole;
-};
-
diff --git a/app/adsb/README.md b/app/adsb/README.md
deleted file mode 100644
index a60c06d02..000000000
--- a/app/adsb/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-## Summary
-
-ADSB code
-Developer: @Luke
-A bit dirty r.n
diff --git a/app/adsb/adsb.cpp b/app/adsb/adsb.cpp
deleted file mode 100644
index 05f5ddfa1..000000000
--- a/app/adsb/adsb.cpp
+++ /dev/null
@@ -1,396 +0,0 @@
-#include "adsb.h"
-#include
-#include
-#include
-
-#ifndef __windows__
-#include
-#endif
-
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-
-
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-#include "markermodel.h"
-#include
-#include "../telemetry/models/fcmavlinksystem.h"
-//#include "localmessage.h"
-
-
-static Adsb* _instance = nullptr;
-
-Adsb* Adsb::instance() {
- if (_instance == nullptr) {
- _instance = new Adsb();
- }
- return _instance;
-}
-
-Adsb::Adsb(QObject *parent): QObject(parent) {
- qDebug() << "Adsb::Adsb()";
-}
-
-void Adsb::onStarted() {
- qDebug() << "------------------Adsb::onStarted()";
-
- #if defined(__rasp_pi__)
- groundAddress = "127.0.0.1";
- #endif
-
- auto markerModel = MarkerModel::instance();
- connect(this, &Adsb::addMarker, markerModel, &MarkerModel::addMarker);
- connect(this, &Adsb::doneAddingMarkers, markerModel, &MarkerModel::doneAddingMarkers);
- connect(this, &Adsb::removeAllMarkers, markerModel, &MarkerModel::removeAllMarkers);
-
- QNetworkAccessManager * manager = new QNetworkAccessManager(this);
-
- m_manager = manager;
-
- connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(processReply(QNetworkReply*))) ;
-
- timer = new QTimer(this);
- connect(timer, &QTimer::timeout, this, &Adsb::requestData);
- // How frequently data is requested
- timer->start(timer_interval);
-}
-
-void Adsb::setGroundIP(QString address) {
- groundAddress = address;
-}
-
-void Adsb::mapBoundsChanged(QGeoCoordinate center_coord) {
- center_lat= center_coord.latitude();
- center_lon= center_coord.longitude();
-
- // api_request_center_lat=setLatitude(center_lat);
- //api_request_center_lon=setLongitude(center_lon);
-
- /*
- need to limit the map bounds to a distance and
- when map orients to drone it breaks api as it expects a box oriented north.
- So defining our own bound box for the api...
- */
-
- auto adsb_distance_limit = settings.value("adsb_distance_limit").toInt();
-
- QGeoCoordinate qgeo_upper_left;
- QGeoCoordinate qgeo_lower_right;
-
- qgeo_upper_left = center_coord.atDistanceAndAzimuth(adsb_distance_limit, 315, 0.0);
- qgeo_lower_right = center_coord.atDistanceAndAzimuth(adsb_distance_limit, 135, 0.0);
-
- upperl_lat= QString::number(qgeo_upper_left.latitude());
- upperl_lon= QString::number(qgeo_upper_left.longitude());
- lowerr_lat= QString::number(qgeo_lower_right.latitude());
- lowerr_lon= QString::number(qgeo_lower_right.longitude());
-
- /*
- qDebug() << "Adsb::lower right=" << lowerr_lat << " " << lowerr_lon;
- qDebug() << "Adsb::upper left=" << upperl_lat << " " << upperl_lon;
- qDebug() << "Adsb::Center=" << center_lat << " " << center_lon;
-*/
-}
-
-void Adsb::set_adsb_api_coord(QGeoCoordinate adsb_api_coord){
- m_adsb_api_coord=adsb_api_coord;
- //qDebug() << "adsb_api_coord=" << m_adsb_api_coord;
- emit adsb_api_coord_changed(m_adsb_api_coord);
-}
-
-void Adsb::requestData() {
-
- qDebug() << "Adsb::requestData()";
- auto show_adsb = settings.value("show_adsb", false).toBool();
-
- adsb_api_sdr = settings.value("adsb_api_sdr").toBool();
-
-
- if (adsb_api_sdr == true){
- //qDebug() << "timer 1";
- timer->stop();
- timer->start(1000);
-
- if (groundAddress.isEmpty()) {
- //LocalMessage::instance()->showMessage("No ADSB Ground Address", 4);
- return;
- }
-
- adsb_url= "http://"+groundAddress+":8080/data/aircraft.json";
- }
- else {
- //qDebug() << "timer 10";
- timer->stop();
- timer->start(10000);
- set_adsb_api_coord(QGeoCoordinate(center_lat,center_lon));
- adsb_url= "https://opensky-network.org/api/states/all?lamin="+lowerr_lat+"&lomin="+upperl_lon+"&lamax="+upperl_lat+"&lomax="+lowerr_lon;
- }
-
- if(show_adsb==false){
- emit removeAllMarkers();
- return;
- }
- qDebug() << "ADSB.cpp URL REQUEST:" << adsb_url;
- QNetworkRequest request;
- QUrl api_request= adsb_url;
- request.setUrl(api_request);
- request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
- qDebug() << "url=" << api_request;
- QNetworkReply *reply = m_manager->get(request);
-}
-
-void Adsb::processReply(QNetworkReply *reply){
-
- QString callsign;
- int contact;
- double lat;
- double lon;
- int alt;
- int track;
- int velocity;
- double vertical;
- qreal distance;
-
- if (reply->error()) {
- qDebug() << "ADSB request error!";
- qDebug() << reply->errorString();
- //LocalMessage::instance()->showMessage("ADSB Reply Error", 4);
- reply->deleteLater();
- return;
- }
-
- QByteArray data = reply->readAll();
-
- QJsonParseError errorPtr;
- QJsonDocument doc = QJsonDocument::fromJson(data, &errorPtr);
-
- if (doc.isNull()) {
- qDebug() << "Parse failed";
-// LocalMessage::instance()->showMessage("ADSB Parse Error", 4);
- }
-
- if(doc.isNull()){
- qDebug()<<"Failed to create JSON doc.";
- reply->deleteLater();
- return;
- }
- if(!doc.isObject()){
- qDebug()<<"JSON is not an object.";
- reply->deleteLater();
- return;
- }
-
- QJsonObject jsonObject = doc.object();
-
- if(jsonObject.isEmpty()){
- qDebug()<<"JSON object is empty.";
- reply->deleteLater();
- return;
- }
-
- // --------------- PARSE FOR SDR ---------------------------------
-
- if (adsb_api_sdr == true){
-
- QJsonArray array = jsonObject["aircraft"].toArray();
-
- //QJsonArray array = doc.array();
-
- if(array.isEmpty()){
- qDebug()<<"JSON array is empty.";
- }
-
- qDebug() << "MYARRAY COUNT=" << array.count();
-
- int current_row=0;
- int last_row=array.count();
-
- emit removeAllMarkers();
-
- if (last_row==0){
- //no markers to add..
- reply->deleteLater();
- return;
- }
-
-
- foreach (const QJsonValue & val, array){
-
- callsign=val.toObject().value("flight").toString();
- if (callsign.length() == 0) {
- callsign = "N/A";
- }
-
- //sdr defaults to imperial and something wacky for speed from dump1090
-
- contact=val.toObject().value("seen_pos").toInt();
- lat=val.toObject().value("lat").toDouble();
- lon=val.toObject().value("lon").toDouble();
- alt=val.toObject().value("altitude").toInt();
- alt=alt*0.3048;
- velocity=val.toObject().value("speed").toDouble();
- velocity=round(velocity*.51418);
- track=val.toObject().value("track").toDouble();
- vertical=val.toObject().value("vert_rate").toDouble();
- vertical=round(vertical*0.3048);
-
-
-
-
- //calculate distance from center of map so we can sort in marker model
- distance = calculateKmDistance(FCMavlinkSystem::instance().lat(), FCMavlinkSystem::instance().lon(), lat, lon);
- emit addMarker(current_row, last_row, Traffic(callsign,contact,lat,lon,alt,velocity,track,vertical,distance));
- current_row=current_row+1;
-
- if (lat!=0 || lon!=0) {
- /*dont evaluate marker if position msg is missing
- above we are adding markers with 0 lat lon cuz we dont know the last row count at loop start
- those "0 position" aircraft are being eliminated in mapcomponent
- */
- evaluateTraffic(callsign, contact, lat, lon, alt, velocity, track, vertical, distance);
- }
-/*
- qDebug() << "callsign=" << callsign;
- qDebug() << "last_contact=" << contact;
- qDebug() << "lat=" << lat;
- qDebug() << "lon=" << lon;
- qDebug() << "alt=" << alt;
- qDebug() << "velocity=" << velocity;
- qDebug() << "track=" << track;
- qDebug() << "vertical=" << vertical;
- qDebug() << "distance=" << distance;
-
- qDebug() << "----------------------------------------------------------";
-*/
-
-
-
- }
-
- }
- // --------------- PARSE FOR API ---------------------------------
- else {
-
- QJsonValue value = jsonObject.value("states");
- QJsonArray array = value.toArray();
-
- qDebug() << "ADSB.cpp OPENSKY ARRAY COUNT=" << array.count();
-
- int current_row=0;
- int last_row=array.count();
-
- QString callsign;
- int contact;
- double lat;
- double lon;
- int alt;
- int track;
- int velocity;
- double vertical;
- qreal distance;
-
- emit removeAllMarkers();
-
- if (last_row==0){
- //no markers to add.. either the api is not happy (too zoomed out) or no traffic to report
- reply->deleteLater();
- return;
- }
-
- foreach (const QJsonValue & v, array){
- QJsonArray innerarray = v.toArray();
-
- callsign=innerarray[1].toString();
- if (callsign.length() == 0) {
- callsign = "N/A";
- }
- contact=innerarray[4].toInt();
- lat=innerarray[6].toDouble();
- lon=innerarray[5].toDouble();
- alt=innerarray[7].toDouble();
- velocity=innerarray[9].toDouble();
- track=innerarray[10].toDouble();
- vertical=innerarray[11].toDouble();
-
- //calculate distance from center of map so we can sort in marker model
-
- distance = calculateKmDistance(FCMavlinkSystem::instance().lat(), FCMavlinkSystem::instance().lon(), lat, lon);
- emit addMarker(current_row, last_row, Traffic(callsign,contact,lat,lon,alt,velocity,track,vertical,distance));
-
- evaluateTraffic(callsign, contact, lat, lon, alt, velocity, track, vertical, distance);
-
- current_row=current_row+1;
-
-/*
- qDebug() << "callsign=" << innerarray[1].toString();
- qDebug() << "last_contact=" << innerarray[4].toInt();
- qDebug() << "lat=" << innerarray[6].toDouble();
- qDebug() << "lon=" << innerarray[5].toDouble();
- qDebug() << "alt=" << innerarray[7].toDouble();
- qDebug() << "velocity=" << innerarray[9].toDouble();
- qDebug() << "track=" << innerarray[10].toDouble();
- qDebug() << "vertical=" << innerarray[11].toDouble();
- qDebug() << "distance=" << distance;
- qDebug() << "----------------------------------------------------------";
-*/
- }
-
- }
- //emit doneAddingMarkers();
- reply->deleteLater();
-}
-
-void Adsb::evaluateTraffic(QString traffic_callsign,
- int traffic_contact,
- double traffic_lat,
- double traffic_lon,
- double traffic_alt,
- double traffic_velocity,
- double traffic_track,
- double traffic_vertical,
- double traffic_distance) {
-
- /*
- * Centralise traffic threat detection here. Once threat is detected it should be
- * labled and then sent over to the adsb widget
- *
- * need to calculate azimuth and bearing of any threats so that it can be shared
- * and depicted in the adsb widget
- */
- int drone_alt = FCMavlinkSystem::instance().altitude_msl_m();
-
- if (traffic_alt - drone_alt < 300 && traffic_distance < 2) {
-// LocalMessage::instance()->showMessage("Aircraft Traffic", 3);
- } else if (traffic_alt - drone_alt < 500 && traffic_distance < 5) {
-// LocalMessage::instance()->showMessage("Aircraft Traffic", 4);
- }
-}
-
-int Adsb::calculateKmDistance(double lat_1, double lon_1,
- double lat_2, double lon_2) {
-
- double latDistance = qDegreesToRadians(lat_1 - lat_2);
- double lngDistance = qDegreesToRadians(lon_1 - lon_2);
-
- double a = qSin(latDistance / 2) * qSin(latDistance / 2)
- + qCos(qDegreesToRadians(center_lat)) * qCos(qDegreesToRadians(lat_2))
- * qSin(lngDistance / 2) * qSin(lngDistance / 2);
-
- double c = 2 * qAtan2(qSqrt(a), qSqrt(1 - a));
- int distance=radius_earth_km * c;
- return distance;
-}
diff --git a/app/adsb/adsb.h b/app/adsb/adsb.h
deleted file mode 100644
index 300a4ebe9..000000000
--- a/app/adsb/adsb.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef ADSB_H
-#define ADSB_H
-
-#include
-#include
-
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include "markermodel.h"
-
-
-class Adsb: public QObject {
- Q_OBJECT
-
-public:
- explicit Adsb(QObject *parent = nullptr);
- static Adsb* instance();
-
- Q_PROPERTY(QGeoCoordinate adsb_api_coord MEMBER m_adsb_api_coord WRITE set_adsb_api_coord NOTIFY adsb_api_coord_changed)
- void set_adsb_api_coord(QGeoCoordinate adsb_api_coord);
-
-signals:
- void addMarker(int current_row, int total_rows, const Traffic &traffic);
- void doneAddingMarkers();
- void removeAllMarkers();
- void adsb_api_coord_changed(QGeoCoordinate adsb_api_coord);
-
-public slots:
- void onStarted();
- void mapBoundsChanged(QGeoCoordinate center_coord);
-
- Q_INVOKABLE void setGroundIP(QString address);
-
-private slots:
- void processReply(QNetworkReply *reply);
- void requestData();
- int calculateKmDistance(double center_lat, double center_lon,
- double marker_lat, double marker_lon);
- void evaluateTraffic(QString callsign,int contact,double lat,double lon,double alt,double velocity,
- double track,double vertical,double distance);
-
-private:
- QGeoCoordinate m_adsb_api_coord;
- QNetworkAccessManager * m_manager;
- QString upperl_lat;
- QString upperl_lon;
- QString lowerr_lat;
- QString lowerr_lon;
- double center_lat;
- double center_lon;
- QSettings settings;
- double radius_earth_km = 6371;
- QString adsb_url;
- int timer_interval = 5000; //get reset later if api or sdr selected
- QTimer *timer;
- bool adsb_api_sdr;
- QString groundAddress;
-};
-
-
-
-#endif
diff --git a/app/adsb/adsb_lib.pri b/app/adsb/adsb_lib.pri
deleted file mode 100644
index e7203bbd3..000000000
--- a/app/adsb/adsb_lib.pri
+++ /dev/null
@@ -1,23 +0,0 @@
-INCLUDEPATH += $$PWD
-
-SOURCES += \
- $$PWD/adsb.cpp \
- $$PWD/markermodel.cpp \
- $$PWD/ADSBVehicle.cpp \
- $$PWD/ADSBVehicleManager.cpp \
- $$PWD/QmlObjectListModel.cpp \
-
-
-HEADERS += \
- $$PWD/adsb.h \
- $$PWD/markermodel.h \
- $$PWD/ADSBVehicle.h \
- $$PWD/ADSBVehicleManager.h \
- $$PWD/QmlObjectListModel.h \
-
-
-QT += positioning
-QT += concurrent
-
-# used in main.cpp / qml to enable/disable adsb depending on weather the needed platform dependencies were found
-DEFINES += QOPENHD_ENABLE_ADSB_LIBRARY
diff --git a/app/adsb/markermodel.cpp b/app/adsb/markermodel.cpp
deleted file mode 100644
index b6725c37a..000000000
--- a/app/adsb/markermodel.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-#include
-#include
-#include
-#include
-
-#include "markermodel.h"
-
-
-
-Traffic::Traffic(const QString &callsign, const int &contact, const double &lat, const double &lon,
- const double &alt, const double &velocity, const double &track, const double &vertical,
- const int &distance)
- : m_callsign(callsign), m_contact(contact), m_lat(lat), m_lon(lon), m_alt(alt),
- m_velocity(velocity), m_track(track), m_vertical(vertical), m_distance(distance)
-{
-}
-
-QString Traffic::callsign() const{
- return m_callsign;
-}
-int Traffic::contact() const{
- return m_contact;
-}
-double Traffic::lat() const{
- return m_lat;
-}
-double Traffic::lon() const{
- return m_lon;
-}
-double Traffic::alt() const{
- return m_alt;
-}
-double Traffic::velocity() const{
- return m_velocity;
-}
-double Traffic::track() const{
- return m_track;
-}
-double Traffic::vertical() const{
- return m_vertical;
-}
-int Traffic::distance() const{
- return m_distance;
-}
-
-
-static MarkerModel* _instance = nullptr;
-
-MarkerModel* MarkerModel::instance() {
- if (_instance == nullptr) {
- _instance = new MarkerModel();
- }
- return _instance;
-}
-
-MarkerModel::MarkerModel(QObject *parent): QAbstractListModel(parent){
- qDebug() << "MarkerModel::MarkerModel()";
-}
-
-void MarkerModel::initMarkerModel() {
- qDebug() << "MarkerModel::initMarkerModel()";
- //auto openSky = OpenSky::instance();
-}
-
-void MarkerModel::addMarker(int current_row, int total_rows, const Traffic &traffic){
-
- if (current_row == 0){
- //LIMIT HOW MANY OF THE NEAREST MARKERS APPEAR
- //m_row_limit = settings.value("adsb_marker_limit").toInt();
-
- beginInsertRows(QModelIndex(), 0, total_rows-1);
- m_traffic.insert(0, traffic);
- }
- else {
- m_traffic.insert(current_row, traffic);
- }
-
- if (current_row == total_rows-1){
- //the last entry has been made
- endInsertRows();
- emit dataChanged(this->index(0),this->index(rowCount()));
- }
- /* old distance sort limiting the rows to nearest X results
- int rowcount=rowCount();
-
- if (rowcount>0){
- for (int i = 0; i < rowcount; ++i) {
- Traffic compare_traffic=m_traffic.at(i);
- if (traffic.distance() < compare_traffic.distance()){
- if(i<=m_row_limit){
- m_traffic.insert(i, traffic);
- }
- break;
- }
- if (i == rowcount-1){
- if(i+1<=m_row_limit){
- m_traffic.insert(i+1, traffic);
- }
- break;
- }
- }
- }
- else {
- //first entry
- m_traffic.insert(0, traffic);
- }
- */
-}
-
-void MarkerModel::doneAddingMarkers(){
- /*
- //NO LONGER CALLED
-
- //qDebug() << "onDoneAddingMarkers rowcount=" << rowCount();
-
- endInsertRows();
-
- // this signal is probably redundant but doesnt seem to hurt. It is ussed by the ADSB widget
- emit dataChanged(this->index(0),this->index(rowCount()));
-
- //get the last displayed row and distance of that object (it is most distant)
- Traffic distant_traffic=m_traffic.at(rowCount()-1);
- set_adsb_radius(distant_traffic.distance()*1000);
- */
-}
-
-void MarkerModel::set_adsb_radius(int adsb_radius){
- //drawing a box now
- m_adsb_radius=adsb_radius;
- //qDebug() << "adsbradius=" << m_adsb_radius;
- emit adsb_radius_changed(m_adsb_radius);
-}
-
-void MarkerModel::removeAllMarkers(){
-
- //qDebug() << "removeallmarker";
- //remove all rows before adding new
-
- beginResetModel();
- //qDeleteAll(m_traffic.begin(), m_traffic.end());
- //qDeleteAll(m_traffic);
- m_traffic.clear();
- endResetModel();
-
- emit dataChanged(this->index(0),this->index(rowCount()));
-
- /*
- int removerowcount=rowCount();
-
- if (removerowcount>0){
- //qDebug() << "begin rowcount= " <index(0),this->index(rowCount()));
- }
- */
-}
-
-
-Traffic MarkerModel::getMarker(int index)const {
- return m_traffic.at(index);
-}
-
-int MarkerModel::rowCount(const QModelIndex &parent) const{
- if (parent.isValid())
- return 0;
- return m_traffic.count();
-}
-
-QVariant MarkerModel::data(const QModelIndex &index, int role) const{
- if (index.row() < 0 || index.row() >= m_traffic.count())
- return QVariant();
-
- const Traffic &traffic = m_traffic[index.row()];
-
- if(role == Callsign)
- return traffic.callsign();
- else if (role == Contact)
- return traffic.contact();
- else if (role == Lat)
- return traffic.lat();
- else if (role == Lon)
- return traffic.lon();
- else if (role == Alt)
- return traffic.alt();
- else if (role == Velocity)
- return traffic.velocity();
- else if (role == Track)
- return traffic.track();
- else if (role == Vertical)
- return traffic.vertical();
- else if (role == Distance)
- return traffic.distance();
- return QVariant();
-}
-
-QHash MarkerModel::roleNames() const{
- QHash roles;
- roles[Callsign] = "callsign";
- roles[Contact] = "contact";
- roles[Lat] = "lat";
- roles[Lon] = "lon";
- roles[Alt] = "alt";
- roles[Velocity] = "velocity";
- roles[Track] = "track";
- roles[Vertical] = "vertical";
- roles[Distance] = "distance";
- return roles;
-}
diff --git a/app/adsb/markermodel.h b/app/adsb/markermodel.h
deleted file mode 100644
index 56bbae3ba..000000000
--- a/app/adsb/markermodel.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef MARKERMODEL_H
-#define MARKERMODEL_H
-#include
-#include
-#include
-#include
-
-class Traffic
-{
-public:
- Traffic(const QString &callsign, const int &contact, const double &lat, const double &lon,
- const double &alt, const double &velocity, const double &track, const double &vertical,
- const int &distance);
-
- QString callsign() const;
- int contact() const;
- double lat() const;
- double lon() const;
- double alt() const;
- double velocity() const;
- double track() const;
- double vertical() const;
- int distance() const;
-
-private:
- QString m_callsign= "---";
- int m_contact= 0;
- double m_lat= 0.0;
- double m_lon= 0.0;
- double m_alt= 99999;
- double m_velocity= 0;
- double m_track= 0.0;
- double m_vertical= 0.0;
- int m_distance= 0;
-};
-
-
-
-class MarkerModel : public QAbstractListModel {
- Q_OBJECT
-
-
-public:
- explicit MarkerModel(QObject *parent = nullptr);
-
- static MarkerModel* instance();
-
- enum MarkerRoles {
- Callsign = Qt::UserRole + 1,
- Contact,
- Lat,
- Lon,
- Alt,
- Velocity,
- Track,
- Vertical,
- Distance
- };
-
- Q_INVOKABLE Traffic getMarker(int index) const;
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
-
- QHash roleNames() const override;
-
- Q_PROPERTY(int adsb_radius MEMBER m_adsb_radius WRITE set_adsb_radius NOTIFY adsb_radius_changed)
- void set_adsb_radius(int adsb_radius);
-
-signals:
- void adsb_radius_changed(int adsb_radius);
-
-public slots:
- void initMarkerModel();
- void addMarker(int current_row , int total_rows, const Traffic &traffic);
- void doneAddingMarkers();
- void removeAllMarkers();
- //int getAdsbRadius();
-
-private:
- QList m_traffic;
- int m_row_limit;
- QSettings settings;
- int m_adsb_radius;
-};
-
-#endif // MARKERMODEL_H
diff --git a/app/common/ThreadsafeQueue.hpp b/app/common/ThreadsafeQueue.hpp
deleted file mode 100644
index 3d1f35564..000000000
--- a/app/common/ThreadsafeQueue.hpp
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// Created by consti10 on 13.02.22.
-//
-
-#ifndef RV1126_OHD_SUSHI_THREADSAFEQUEUE_HPP
-#define RV1126_OHD_SUSHI_THREADSAFEQUEUE_HPP
-
-#include
-#include
-#include
-#include
-
-// NOTE: the item is wrapped as std::shared_ptr
-template
-class ThreadsafeQueue {
- std::queue> queue_;
- mutable std::mutex mutex_;
- // Moved out of public interface to prevent races between this
- // and pop().
- bool empty() const {
- return queue_.empty();
- }
-public:
- ThreadsafeQueue() = default;
- ThreadsafeQueue(const ThreadsafeQueue &) = delete ;
- ThreadsafeQueue& operator=(const ThreadsafeQueue &) = delete ;
- ThreadsafeQueue(ThreadsafeQueue&& other) {
- std::lock_guard lock(mutex_);
- queue_ = std::move(other.queue_);
- }
- virtual ~ThreadsafeQueue() { }
- unsigned long size() const {
- std::lock_guard lock(mutex_);
- return queue_.size();
- }
- // returns the oldest item in the queue if available
- // nullptr otherwise
- std::shared_ptr popIfAvailable() {
- std::lock_guard lock(mutex_);
- if (queue_.empty()) {
- return std::shared_ptr(nullptr);
- }
- auto tmp = queue_.front();
- queue_.pop();
- return tmp;
- }
- // adds a new item to the queue
- void push(std::shared_ptr item) {
- std::lock_guard lock(mutex_);
- queue_.push(std::move(item));
- }
- // returns a list of all buffers currently inside the queue and removes them from the queue
- // The first element in the returned list is the oldest element in the queue
- std::vector> getAllAndClear(){
- std::lock_guard lock(mutex_);
- std::vector> ret;
- while (!queue_.empty()){
- ret.push_back(queue_.front());
- queue_.pop();
- }
- return ret;
- }
-};
-
-
-// Not sure how to call this, from drmprime example
-// blocking, cannot put a new buffer in until the last buffer has been consumed
-// after creation, you can put in a buffer immediately
-// Then, you have to wait until this buffer has been consumed before you can put in the next buffer
-template
-class ThreadsafeSingleBuffer{
-public:
- ThreadsafeSingleBuffer(){
- sem_init(&q_sem_in, 0, 0);
- sem_init(&q_sem_out, 0, 0);
- // in the beginning, we can accept a new buffer immediately
- int ret=sem_post(&q_sem_out);
- /*if(ret!=0){
- MLOGD<<"Error\n";
- }else{
- MLOGD<<"Success\n";
- }*/
- }
- ~ThreadsafeSingleBuffer(){
- sem_destroy(&q_sem_in);
- sem_destroy(&q_sem_out);
- }
- // blocks until buffer is available
- // or terminate() has been called from another thread
- T getBuffer(){
- //MLOGD<<"A1\n";
- sem_wait(&q_sem_in);
- auto ret=q_buffer;
- q_buffer=NULL;
- sem_post(&q_sem_out);
- //MLOGD<<"A2\n";
- return ret;
- }
- // blocks until the current buffer has been consumed
- // and therefore can be updated to a new value
- void setBuffer(T newBuffer){
- //MLOGD<<"X1\n";
- sem_wait(&q_sem_out);
- //assert(message==NULL);
- q_buffer=newBuffer;
- sem_post(&q_sem_in);
- //MLOGD<<"X2\n";
- }
- // terminate, getBuffer() will return immediately
- void terminate(){
- q_terminate= true;
- sem_post(&q_sem_in);
- }
- // returns true when terminated
- bool terminated(){
- return q_terminate;
- }
- // be carefully, not synchronized at all
- T unsafeGetFrame(){
- return q_buffer;
- }
-private:
- sem_t q_sem_in;
- sem_t q_sem_out;
- // terminate
- bool q_terminate=false;
- T q_buffer=NULL;
-};
-
-
-#endif //RV1126_OHD_SUSHI_THREADSAFEQUEUE_HPP
diff --git a/app/logging/hudlogmessagesmodel.cpp b/app/logging/hudlogmessagesmodel.cpp
index 2bb0011e3..91a6cd76f 100644
--- a/app/logging/hudlogmessagesmodel.cpp
+++ b/app/logging/hudlogmessagesmodel.cpp
@@ -106,6 +106,7 @@ void HUDLogMessagesModel::handle_cleanup()
const auto age=std::chrono::steady_clock::now()-el.added_time_point;
if(age>std::chrono::seconds(5)){
removeData(i);
+ i--;
}
}
}
diff --git a/app/logging/hudlogmessagesmodel.h b/app/logging/hudlogmessagesmodel.h
index dbf428359..95a458a75 100644
--- a/app/logging/hudlogmessagesmodel.h
+++ b/app/logging/hudlogmessagesmodel.h
@@ -51,7 +51,7 @@ public slots:
QVector m_data;
QTimer* m_cleanup_timer;
void handle_cleanup();
- static constexpr int MAX_N_ELEMENTS=5;
+ static constexpr int MAX_N_ELEMENTS=6;
public:
signals:
void signalAddLogMessage(int severity,QString message);
diff --git a/app/logging/logmessagesmodel.cpp b/app/logging/logmessagesmodel.cpp
index ee1b97fb5..91c218b2a 100644
--- a/app/logging/logmessagesmodel.cpp
+++ b/app/logging/logmessagesmodel.cpp
@@ -108,10 +108,12 @@ void LogMessagesModel::removeData(int row)
void LogMessagesModel::addData(LogMessageData logMessageData)
{
- // hacky temporary
- if(logMessageData.message.contains("Scanning ")){
- HUDLogMessagesModel::instance().add_message_info(logMessageData.message);
- }else if(logMessageData.message.contains("Cannot scan ")){
+ // A few important log(s) we show in the HUD
+ if(logMessageData.message.contains("TX (likely) not supported by card(s)")){
+ //HUDLogMessagesModel::instance().add_message_warning(logMessageData.message);
+ }else if(logMessageData.message.contains("Bind phrase mismatch")){
+ HUDLogMessagesModel::instance().add_message_warning(logMessageData.message);
+ }else if(logMessageData.message.contains("error - unsupported resolution ?")){
HUDLogMessagesModel::instance().add_message_warning(logMessageData.message);
}
//qDebug()<<"LogMessagesModel::addData"< permissions({"android.permission.INTERNET",
"android.permission.ACCESS_FINE_LOCATION"});
#endif
-#ifdef QOPENHD_HAS_MAVSDK_MAVLINK_TELEMETRY
#include "telemetry/models/fcmavlinksystem.h"
+#include "telemetry/action/fcaction.h"
+#include "telemetry/action/ohdaction.h"
#include "telemetry/models/fcmavlinkmissionitemsmodel.h"
-#include "telemetry/models/fcmavlinksettingsmodel.h"
+#include "telemetry/action/fcmissionhandler.h"
#include "telemetry/models/camerastreammodel.h"
#include "telemetry/models/aohdsystem.h"
#include "telemetry/models/wificard.h"
#include "telemetry/MavlinkTelemetry.h"
#include "telemetry/models/rcchannelsmodel.h"
#include "telemetry/settings/mavlinksettingsmodel.h"
-#include "telemetry/settings/synchronizedsettings.h"
-#endif //QOPENHD_HAS_MAVSDK_MAVLINK_TELEMETRY
-
+#include "telemetry/settings/wblinksettingshelper.h"
#include "osd/speedladder.h"
#include "osd/altitudeladder.h"
#include "osd/headingladder.h"
#include "osd/horizonladder.h"
#include "osd/flightpathvector.h"
-#include "osd/drawingcanvas.h"
#include "osd/aoagauge.h"
#include "osd/performancehorizonladder.h"
@@ -65,12 +63,6 @@ const QVector permissions({"android.permission.INTERNET",
#include "util/WorkaroundMessageBox.h"
#include "util/restartqopenhdmessagebox.h"
-#ifdef QOPENHD_ENABLE_ADSB_LIBRARY
-#include "adsb/ADSBVehicleManager.h"
-#include "adsb/ADSBVehicle.h"
-#include "adsb/QmlObjectListModel.h"
-#endif
-
// Load all the fonts we use ?!
static void load_fonts(){
@@ -263,7 +255,6 @@ int main(int argc, char *argv[]) {
qmlRegisterType("OpenHD", 1, 0, "HeadingLadder");
qmlRegisterType("OpenHD", 1, 0, "HorizonLadder");
qmlRegisterType("OpenHD", 1, 0, "FlightPathVector");
- qmlRegisterType("OpenHD", 1, 0, "DrawingCanvas");
qmlRegisterType("OpenHD", 1, 0, "AoaGauge");
qmlRegisterType("OpenHD", 1, 0, "PerformanceHorizonLadder");
@@ -271,42 +262,44 @@ int main(int argc, char *argv[]) {
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("_qopenhd", &QOpenHD::instance());
QOpenHD::instance().setEngine(&engine);
+ write_platform_context_properties(engine);
// Regster all the QT Mavlink system model(s)
// it is a common practice for QT to prefix models from c++ with an underscore
+ // Needs to be registered first, otherwise we can have threading issue(s)
+ engine.rootContext()->setContextProperty("_messageBoxInstance", &WorkaroundMessageBox::instance());
+ engine.rootContext()->setContextProperty("_restartqopenhdmessagebox", &RestartQOpenHDMessageBox::instance());
engine.rootContext()->setContextProperty("_qrenderstats", &QRenderStats::instance());
- write_platform_context_properties(engine);
engine.rootContext()->setContextProperty("_ohdlogMessagesModel", &LogMessagesModel::instanceOHD());
engine.rootContext()->setContextProperty("_fclogMessagesModel", &LogMessagesModel::instanceFC());
engine.rootContext()->setContextProperty("_hudLogMessagesModel", &HUDLogMessagesModel::instance());
-#ifdef QOPENHD_HAS_MAVSDK_MAVLINK_TELEMETRY
- // Telemetry
+ // Telemetry - first all the models
engine.rootContext()->setContextProperty("_airCameraSettingsModel", &MavlinkSettingsModel::instanceAirCamera());
engine.rootContext()->setContextProperty("_airCameraSettingsModel2", &MavlinkSettingsModel::instanceAirCamera2());
- engine.rootContext()->setContextProperty("_airPiSettingsModel", &MavlinkSettingsModel::instanceAir());
- engine.rootContext()->setContextProperty("_groundPiSettingsModel", &MavlinkSettingsModel::instanceGround());
- // exp
- //engine.rootContext()->setContextProperty("_fcSettingsModel", &MavlinkSettingsModel::instanceFC());
- engine.rootContext()->setContextProperty("_synchronizedSettings", &SynchronizedSettings::instance());
- engine.rootContext()->setContextProperty("_mavlinkTelemetry", &MavlinkTelemetry::instance());
+ engine.rootContext()->setContextProperty("_ohdSystemAirSettingsModel", &MavlinkSettingsModel::instanceAir());
+ engine.rootContext()->setContextProperty("_ohdSystemGroundSettings", &MavlinkSettingsModel::instanceGround());
+ engine.rootContext()->setContextProperty("_wbLinkSettingsHelper", &WBLinkSettingsHelper::instance());
engine.rootContext()->setContextProperty("_fcMavlinkSystem", &FCMavlinkSystem::instance());
+ engine.rootContext()->setContextProperty("_fcMavlinkAction", &FCAction::instance());
engine.rootContext()->setContextProperty("_fcMavlinkMissionItemsModel", &FCMavlinkMissionItemsModel::instance());
- engine.rootContext()->setContextProperty("_fcMavlinkkSettingsModel", &FCMavlinkSettingsModel::instance());
+ engine.rootContext()->setContextProperty("_fcMavlinkMissionHandler", &FCMissionHandler::instance());
engine.rootContext()->setContextProperty("_rcchannelsmodelground", &RCChannelsModel::instanceGround());
engine.rootContext()->setContextProperty("_rcchannelsmodelfc", &RCChannelsModel::instanceFC());
engine.rootContext()->setContextProperty("_ohdSystemAir", &AOHDSystem::instanceAir());
engine.rootContext()->setContextProperty("_ohdSystemGround", &AOHDSystem::instanceGround());
engine.rootContext()->setContextProperty("_cameraStreamModelPrimary", &CameraStreamModel::instance(0));
engine.rootContext()->setContextProperty("_cameraStreamModelSecondary", &CameraStreamModel::instance(1));
+ engine.rootContext()->setContextProperty("_ohdAction", &OHDAction::instance());
engine.rootContext()->setContextProperty("_wifi_card_gnd0", &WiFiCard::instance_gnd(0));
engine.rootContext()->setContextProperty("_wifi_card_gnd1", &WiFiCard::instance_gnd(1));
engine.rootContext()->setContextProperty("_wifi_card_gnd2", &WiFiCard::instance_gnd(2));
engine.rootContext()->setContextProperty("_wifi_card_gnd3", &WiFiCard::instance_gnd(3));
engine.rootContext()->setContextProperty("_wifi_card_air", &WiFiCard::instance_air());
-#endif //QOPENHD_HAS_MAVSDK_MAVLINK_TELEMETRY
+ // And then the main part
+ engine.rootContext()->setContextProperty("_mavlinkTelemetry", &MavlinkTelemetry::instance());
// Platform - dependend video begin -----------------------------------------------------------------
#ifdef QOPENHD_ENABLE_GSTREAMER_QMLGLSINK
@@ -351,23 +344,6 @@ int main(int argc, char *argv[]) {
// Platform - dependend video end -----------------------------------------------------------------
engine.rootContext()->setContextProperty("_decodingStatistics",&DecodingStatistcs::instance());
- // dirty
- engine.rootContext()->setContextProperty("_messageBoxInstance", &WorkaroundMessageBox::instance());
- engine.rootContext()->setContextProperty("_restartqopenhdmessagebox", &RestartQOpenHDMessageBox::instance());
-
-#ifdef QOPENHD_ENABLE_ADSB_LIBRARY
- qmlRegisterUncreatableType("OpenHD", 1, 0, "QmlObjectListModel", "Reference only");
- engine.rootContext()->setContextProperty("QOPENHD_ENABLE_ADSB_LIBRARY", QVariant(true));
- engine.rootContext()->setContextProperty("EnableADSB", QVariant(true));
- engine.rootContext()->setContextProperty("LimitADSBMax", QVariant(true));
- auto adsbVehicleManager = ADSBVehicleManager::instance();
- engine.rootContext()->setContextProperty("AdsbVehicleManager", adsbVehicleManager);
- //QObject::connect(openHDSettings, &OpenHDSettings::groundStationIPUpdated, adsbVehicleManager, &ADSBVehicleManager::setGroundIP, Qt::QueuedConnection);
- adsbVehicleManager->onStarted();
-#else
- engine.rootContext()->setContextProperty("QOPENHD_ENABLE_ADSB_LIBRARY", QVariant(false));
- engine.rootContext()->setContextProperty("EnableADSB", QVariant(false));
-#endif
// This allows to use the defines as strings in qml
engine.rootContext()->setContextProperty("QOPENHD_GIT_VERSION",
@@ -392,6 +368,8 @@ int main(int argc, char *argv[]) {
#endif
qDebug() << "Running QML";
+ // Now we start mavlink for the first time
+ MavlinkTelemetry::instance().start();
QRenderStats::instance().register_to_root_window(engine);
diff --git a/app/osd/drawingcanvas.cpp b/app/osd/drawingcanvas.cpp
deleted file mode 100644
index bbcf95a6a..000000000
--- a/app/osd/drawingcanvas.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-#include "drawingcanvas.h"
-
-#include
-#include
-#include
-#include
-#include
-
-#include "debug_overdraw.hpp"
-
-DrawingCanvas::DrawingCanvas(QQuickItem *parent): QQuickPaintedItem(parent) {
- //qDebug() << "DrawingCanvas::DrawingCanvas()";
- setRenderTarget(RenderTarget::FramebufferObject);
-
- //set font to pixels size early
- m_font.setPixelSize(14);
- m_fontNormal.setPixelSize(35);
-
- QSettings settings;
-}
-
-void DrawingCanvas::paint(QPainter* painter) {
- painter->save();
- if(ENABLE_DEBUG_OVERDRAW){
- setFillColor(QColor::fromRgb(255,0,0,128));
- }
-
- if (m_draw_request=="adsb"){ //statis for now, but here for future build out
- auto pos_x= 130;//the middle
- auto pos_y= 130;
-
- painter->setPen(m_color);
- setOpacity(1.0);
-
- painter->translate(pos_x,pos_y);
-
- painter->rotate(-90);//glyph is oriented +90
-
-
- bool orientation_setting = settings.value("map_orientation").toBool();
-
- if (orientation_setting == true){ //orienting map to drone
- m_orientation = m_heading - m_drone_heading;
-
- if (m_orientation < 0) m_orientation += 360;
- if (m_orientation >= 360) m_orientation -=360;
- painter->rotate(m_orientation);
- }
- else{ //orienting map to north
- m_orientation=0;
- painter->rotate(m_heading);
- }
-
- //draw speed tail
- painter->setOpacity(0.5);
- painter->fillRect(QRectF(0, -8, -m_speed/12, 4), "white");
- painter->setPen("grey");
- painter->drawRect(QRectF(0, -8, -m_speed/12, 4));
-
- //add icon glyph of airplane
- /* //for glow effect
- painter->setOpacity(1.0);
- painter->setPen("grey");
- painter->setFont(m_fontBig);
- painter->drawText(0, 0, "\ue3d0");
- */
-
- painter->setOpacity(1.0);
- painter->setPen("black");
- painter->setFont(m_fontNormal);
-
- painter->drawText(0, 0, "\uf072");
-
- //draw data block
-
- painter->translate(+50,-60); //+up -down, -left +right
-
- //de-rotate whatever was done above and the adjustment for the glyph
- if (m_orientation!=0){
- painter->rotate(-m_orientation+90);
- }
- else {
- painter->rotate(-m_heading+90);
- }
-
- painter->translate(-33,-24); //preposition the text block
-
- painter->setOpacity(0.5);
- QPainterPath path;
- path.addRoundedRect(QRectF(0, 0, 80, 50), 10, 10);
- QPen pen(Qt::white, 2);
- painter->setPen(pen);
- painter->fillPath(path, Qt::black);
- painter->drawPath(path);
-
- painter->setOpacity(1.0);
- painter->setPen("white");
- painter->setFont(m_font);
-
- painter->drawText(5, 15, m_name);
- painter->drawText(10, 30, m_speed_text);
- painter->drawText(10, 45, m_alt_text);
-
- painter->restore();
- }
-}
-
-
-
-QColor DrawingCanvas::color() const {
- return m_color;
-}
-
-QColor DrawingCanvas::glow() const {
- return m_glow;
-}
-
-void DrawingCanvas::setColor(QColor color) {
- m_color = color;
- emit colorChanged(m_color);
- update();
-}
-
-void DrawingCanvas::setGlow(QColor glow) {
- m_glow = glow;
- emit glowChanged(m_glow);
- update();
-}
-
-void DrawingCanvas::setFpvInvertPitch(bool fpvInvertPitch) {
- m_fpvInvertPitch = fpvInvertPitch;
- emit fpvInvertPitchChanged(m_fpvInvertPitch);
- update();
-}
-
-void DrawingCanvas::setFpvInvertRoll(bool fpvInvertRoll) {
- m_fpvInvertRoll = fpvInvertRoll;
- emit fpvInvertRollChanged(m_fpvInvertRoll);
- update();
-}
-
-void DrawingCanvas::setHeading(int heading) {
- m_heading = heading;
- emit headingChanged(m_heading);
- update();
-}
-
-void DrawingCanvas::setDroneHeading(int drone_heading) {
- m_drone_heading = drone_heading;
- emit droneHeadingChanged(m_drone_heading);
- update();
-}
-
-void DrawingCanvas::setAlt(int alt) {
- m_alt = alt;
-
- if(alt>9999){
- m_alt_text="---";
- }
- else{
- imperial = settings.value("enable_imperial").toBool();
- if (imperial == false){
- m_alt_text = (QString::number(round(alt)))+" M";
- }
- else{
- m_alt_text = (QString::number(round((alt) * 3.28084)))+" Ft";
- }
- }
-
- emit altChanged(m_alt);
- emit altTextChanged(m_alt_text);
- update();
-}
-
-void DrawingCanvas::setAltText(QString alt_text) {
- m_alt_text = alt_text;
- emit altTextChanged(m_alt_text);
- update();
-}
-
-void DrawingCanvas::setDroneAlt(int drone_alt) {
- m_drone_alt = drone_alt;
- emit droneAltChanged(m_drone_alt);
- update();
-}
-
-void DrawingCanvas::setSpeed(int speed) {
- if(speed>9999){
- m_speed=0;
- m_speed_text="---";
- }
- else{
- imperial = settings.value("enable_imperial").toBool();
- if (imperial == false){
- m_speed =round(speed* 3.6);
- m_speed_text = (QString::number(round(speed* 3.6)))+" Kph";
- }
- else{
- m_speed = round(speed* 2.23694);
- m_speed_text = (QString::number(round((speed* 2.23694))))+" Mph";
- }
- }
-
- emit speedTextChanged(m_speed_text);
- emit speedChanged(m_speed);
- update();
-}
-
-void DrawingCanvas::setSpeedText(QString speed_text) {
- m_speed_text = speed_text;
- emit speedTextChanged(m_speed_text);
- update();
-}
-
-void DrawingCanvas::setVertSpd(int vert_spd) {
- m_vert_spd = vert_spd;
- emit vertSpdChanged(m_vert_spd);
- update();
-}
-
-void DrawingCanvas::setRoll(int roll) {
- m_roll = roll;
- emit rollChanged(m_roll);
- update();
-}
-
-void DrawingCanvas::setPitch(int pitch) {
- m_pitch = pitch;
- emit pitchChanged(m_pitch);
- update();
-}
-
-void DrawingCanvas::setLateral(int lateral) {
- m_lateral = lateral;
- emit lateralChanged(m_lateral);
- update();
-}
-
-void DrawingCanvas::setVertical(int vertical) {
- m_vertical = vertical;
- emit verticalChanged(m_vertical);
- update();
-}
-
-void DrawingCanvas::setHorizonSpacing(int horizonSpacing) {
- m_horizonSpacing = horizonSpacing;
- emit horizonSpacingChanged(m_horizonSpacing);
- update();
-}
-
-void DrawingCanvas::setHorizonWidth(double horizonWidth) {
- m_horizonWidth = horizonWidth;
- emit horizonWidthChanged(m_horizonWidth);
- update();
-}
-
-void DrawingCanvas::setSize(double size) {
- m_size = size;
- emit sizeChanged(m_size);
- update();
-}
-
-void DrawingCanvas::setName(QString name) {
- m_name = name;
- emit nameChanged(m_name);
- update();
-}
-
-void DrawingCanvas::setVerticalLimit(double verticalLimit) {
- m_verticalLimit = verticalLimit;
- emit verticalLimitChanged(m_verticalLimit);
- update();
-}
-
-void DrawingCanvas::setLateralLimit(double lateralLimit) {
- m_lateralLimit = lateralLimit;
- emit lateralLimitChanged(m_lateralLimit);
- update();
-}
-
-void DrawingCanvas::setFontFamily(QString fontFamily) {
- m_fontFamily = fontFamily;
- emit fontFamilyChanged(m_fontFamily);
- update();
-}
diff --git a/app/osd/drawingcanvas.h b/app/osd/drawingcanvas.h
deleted file mode 100644
index 5177f20b6..000000000
--- a/app/osd/drawingcanvas.h
+++ /dev/null
@@ -1,150 +0,0 @@
-#include
-#include
-#include
-#include
-
-class DrawingCanvas : public QQuickPaintedItem {
- Q_OBJECT
- Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
- Q_PROPERTY(QColor glow READ glow WRITE setGlow NOTIFY glowChanged)
- Q_PROPERTY(bool fpvInvertPitch MEMBER m_fpvInvertPitch WRITE setFpvInvertPitch NOTIFY fpvInvertPitchChanged)
- Q_PROPERTY(bool fpvInvertRoll MEMBER m_fpvInvertRoll WRITE setFpvInvertRoll NOTIFY fpvInvertRollChanged)
-
- Q_PROPERTY(int alt MEMBER m_alt WRITE setAlt NOTIFY altChanged)
- Q_PROPERTY(QString alt_text MEMBER m_alt_text WRITE setAltText NOTIFY altTextChanged)
- Q_PROPERTY(int drone_alt MEMBER m_drone_alt WRITE setDroneAlt NOTIFY droneAltChanged)
- Q_PROPERTY(int speed MEMBER m_speed WRITE setSpeed NOTIFY speedChanged)
- Q_PROPERTY(QString speed_text MEMBER m_speed_text WRITE setSpeedText NOTIFY speedTextChanged)
- Q_PROPERTY(int vert_spd MEMBER m_vert_spd WRITE setVertSpd NOTIFY vertSpdChanged)
- Q_PROPERTY(int heading MEMBER m_heading WRITE setHeading NOTIFY headingChanged)
- Q_PROPERTY(int drone_heading MEMBER m_drone_heading WRITE setDroneHeading NOTIFY droneHeadingChanged)
- Q_PROPERTY(int roll MEMBER m_roll WRITE setRoll NOTIFY rollChanged)
- Q_PROPERTY(int pitch MEMBER m_pitch WRITE setPitch NOTIFY pitchChanged)
-
- Q_PROPERTY(int lateral MEMBER m_lateral WRITE setLateral NOTIFY lateralChanged)
- Q_PROPERTY(int vertical MEMBER m_vertical WRITE setVertical NOTIFY verticalChanged)
-
- Q_PROPERTY(int horizonSpacing MEMBER m_horizonSpacing WRITE setHorizonSpacing NOTIFY horizonSpacingChanged)
- Q_PROPERTY(double horizonWidth MEMBER m_horizonWidth WRITE setHorizonWidth NOTIFY horizonWidthChanged)
- Q_PROPERTY(double size MEMBER m_size WRITE setSize NOTIFY sizeChanged)
-
- Q_PROPERTY(QString name MEMBER m_name WRITE setName NOTIFY nameChanged)
-
- Q_PROPERTY(double verticalLimit MEMBER m_verticalLimit WRITE setVerticalLimit NOTIFY verticalLimitChanged)
- Q_PROPERTY(double lateralLimit MEMBER m_lateralLimit WRITE setLateralLimit NOTIFY lateralLimitChanged)
-
- Q_PROPERTY(QString fontFamily MEMBER m_fontFamily WRITE setFontFamily NOTIFY fontFamilyChanged)
-
-public:
- explicit DrawingCanvas(QQuickItem* parent = nullptr);
-
- void paint(QPainter* painter) override;
-
- QColor color() const;
- QColor glow() const;
-
-public slots:
- void setColor(QColor color);
- void setGlow(QColor glow);
- void setFpvInvertPitch(bool fpvInvertPitch);
- void setFpvInvertRoll(bool fpvInvertRoll);
-
- void setAlt(int alt);
- void setAltText(QString alt_text);
- void setDroneAlt(int drone_alt);
- void setSpeed(int speed);
- void setSpeedText(QString speed_text);
- void setVertSpd(int vert_spd);
- void setHeading(int heading);
- void setDroneHeading(int drone_heading);
- void setRoll(int roll);
- void setPitch(int pitch);
-
- void setLateral(int lateral);
- void setVertical(int vertical);
-
- void setHorizonSpacing(int horizonSpacing);
- void setHorizonWidth(double horizonWidth);
- void setSize(double size);
-
- void setName(QString name);
-
- void setVerticalLimit(double verticalLimit);
- void setLateralLimit(double lateralLimit);
-
- void setFontFamily(QString fontFamily);
-
-signals:
- void colorChanged(QColor color);
- void glowChanged(QColor glow);
- void fpvInvertPitchChanged(bool fpvInvertPitch);
- void fpvInvertRollChanged(bool fpvInvertRoll);
-
- void altChanged(int alt);
- void altTextChanged(QString alt_text);
- void droneAltChanged(int drone_alt);
- void speedChanged(int speed);
- void speedTextChanged(QString speed_text);
- void vertSpdChanged(int vert_spd);
- void headingChanged(int heading);
- void droneHeadingChanged(int drone_heading);
- void rollChanged(int roll);
- void pitchChanged(int pitch);
-
- void lateralChanged(int lateral);
- void verticalChanged(int vertical);
-
- void horizonSpacingChanged(int horizonSpacing);
- void horizonWidthChanged(double horizonWidth);
- void sizeChanged(double size);
-
- void nameChanged(QString name);
-
- void verticalLimitChanged(double verticalLimit);
- void lateralLimitChanged(double lateralLimit);
-
- void fontFamilyChanged(QString fontFamily);
-
-private:
- QColor m_color;
- QColor m_glow;
- bool m_fpvInvertPitch;
- bool m_fpvInvertRoll;
-
- int m_heading;
- int m_drone_heading;
- int m_alt;
- QString m_alt_text;
- int m_drone_alt;
- int m_speed;
- QString m_speed_text;
- int m_vert_spd;
- int m_roll;
- int m_pitch;
-
- int m_lateral;
- int m_vertical;
-
- int m_horizonSpacing;
- double m_horizonWidth;
- double m_size;
-
- QString m_name;
-
- double m_verticalLimit;
- double m_lateralLimit;
-
- QSettings settings;
- bool imperial;
-
- int m_orientation=0;
-
- QString m_fontFamily;
-
- QString m_draw_request="adsb"; //for future build out of more draw requests
-
- QFont m_font = QFont("Font Awesome 5 Free", 10, QFont::Bold, false);
- QFont m_fontNormal = QFont("osdicons", 25 , QFont::PreferAntialias, true);
- //QFont m_fontBig = QFont("osdicons", 25*1.1, QFont::PreferAntialias, true);
-
-};
diff --git a/app/platform/README.md b/app/platform/README.md
deleted file mode 100644
index 5cad9121d..000000000
--- a/app/platform/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Summary
-Here we can place code that is platform-dependendent.( and not already abstracted by QT).
-For example, changing the screen brightness works differently on different platforms
diff --git a/app/platform/appleplatform.h b/app/platform/appleplatform.h
deleted file mode 100644
index 0bd8cb5af..000000000
--- a/app/platform/appleplatform.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef APPLEPLATFORM_H
-#define APPLEPLATFORM_H
-
-#include
-
-class ApplePlatform: public QObject {
- Q_OBJECT
-
-public:
- explicit ApplePlatform(QObject *parent = nullptr);
- static ApplePlatform* instance();
-
-signals:
- void willEnterForeground();
- void didEnterBackground();
-
-public:
-
- void disableScreenLock();
-
- void registerNotifications();
-};
-
-#endif // APPLEPLATFORM_H
diff --git a/app/platform/appleplatform.mm b/app/platform/appleplatform.mm
deleted file mode 100644
index 5e1421409..000000000
--- a/app/platform/appleplatform.mm
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-#include "appleplatform.h"
-
-#import
-#import
-
-
-static ApplePlatform* _instance = nullptr;
-
-ApplePlatform* ApplePlatform::instance() {
- if (_instance == nullptr) {
- _instance = new ApplePlatform();
- }
- return _instance;
-}
-
-
-ApplePlatform::ApplePlatform(QObject *parent): QObject(parent) {
-
-}
-
-
-void ApplePlatform::disableScreenLock() {
- [[UIApplication sharedApplication] setIdleTimerDisabled: YES];
-}
-
-
-void ApplePlatform::registerNotifications() {
- NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
-
- [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification
- object:nil
- queue:mainQueue
- usingBlock:^void(NSNotification *notification) {
- emit didEnterBackground();
- }];
-
- [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification
- object:nil
- queue:mainQueue
- usingBlock:^void(NSNotification *notification) {
- emit willEnterForeground();
- }];
-}
diff --git a/app/telemetry/MavlinkTelemetry.cpp b/app/telemetry/MavlinkTelemetry.cpp
index fd88d9c8e..b8a70d995 100644
--- a/app/telemetry/MavlinkTelemetry.cpp
+++ b/app/telemetry/MavlinkTelemetry.cpp
@@ -1,71 +1,18 @@
#include "MavlinkTelemetry.h"
-#include "common/openhd-util.hpp"
-#include "mavsdk_helper.hpp"
-#include "qopenhdmavlinkhelper.hpp"
-#include "telemetry/openhd_defines.hpp"
#include "models/aohdsystem.h"
#include "models/fcmavlinksystem.h"
#include "settings/mavlinksettingsmodel.h"
-#include "../logging/logmessagesmodel.h"
+#include "util/qopenhdmavlinkhelper.hpp"
+
+#include "action/fcmissionhandler.h"
+#include "action/impl/cmdsender.h"
+#include "action/fcmsgintervalhandler.h"
+#include "action/impl/xparam.h"
MavlinkTelemetry::MavlinkTelemetry(QObject *parent):QObject(parent)
{
- m_msg_interval_helper=std::make_unique();
- mavsdk::Mavsdk::Configuration config{QOpenHDMavlinkHelper::get_own_sys_id(),QOpenHDMavlinkHelper::get_own_comp_id(),false};
- mavsdk=std::make_shared();
- mavsdk->set_configuration(config);
- mavsdk::log::subscribe([](mavsdk::log::Level level, // message severity level
- const std::string& message, // message text
- const std::string& file, // source file from which the message was sent
- int line) { // line number in the source file
- // process the log message in a way you like
- qDebug()<<"MAVSDK::"<=mavsdk::log::Level::Warn){
- // LogMessagesModel::instance().addLogMessage("T",message.c_str(),0);
- //}
- // returning true from the callback disables printing the message to stdout
- //return level < mavsdk::log::Level::Warn;
- return true;
- });
- // NOTE: subscribe before adding any connection(s)
- mavsdk->subscribe_on_new_system([this]() {
- std::lock_guard lock(systems_mutex);
- // hacky, fucking hell. mavsdk might call this callback with more than 1 system added.
- auto systems=mavsdk->systems();
- for(auto i=mavsdk_already_known_systems;ionNewSystem(new_system);
- }
- mavsdk_already_known_systems=systems.size();
- //qDebug()<mavsdk->systems().size();
- //auto system = this->mavsdk->systems().back();
- //this->onNewSystem(system);
- });
- QSettings settings;
- dev_use_tcp = settings.value("dev_mavlink_via_tcp",false).toBool();
- if(dev_use_tcp){
- dev_tcp_server_ip=settings.value("dev_mavlink_tcp_ip","0.0.0.0").toString().toStdString();
- if(!OHDUtil::is_valid_ip(dev_tcp_server_ip)){
- qWarning("%s not a valid ip, using default",dev_tcp_server_ip.c_str());
- dev_tcp_server_ip = "0.0.0.0";
- }
- //dev_tcp_server_ip = "0.0.0.0";
- // We try connecting until success
- m_tcp_connect_thread=std::make_unique(&MavlinkTelemetry::tcp_only_establish_connection,this);
- }else{
- // default, udp, passive (like QGC)
- mavsdk::ConnectionResult connection_result = mavsdk->add_udp_connection(QOPENHD_GROUND_CLIENT_UDP_PORT_IN);
- std::stringstream ss;
- ss<<"MAVSDK UDP connection: " << connection_result;
- qDebug()<setContextProperty("_mavlinkTelemetry", &MavlinkTelemetry::instance());
-}
-
-void MavlinkTelemetry::onNewSystem(std::shared_ptr system){
- const auto components=system->component_ids();
- qDebug()<<"System found"<<(int)system->get_system_id()<<" with components:"<get_system_id()==OHD_SYS_ID_GROUND){
- qDebug()<<"Found OHD Ground station";
- systemOhdGround=system;
- passtroughOhdGround=std::make_shared(system);
- qDebug()<<"XX:"<get_target_sysid();
- passtroughOhdGround->intercept_incoming_messages_async([this](mavlink_message_t& msg){
- //qDebug()<<"Intercept:Got message"<intercept_outgoing_messages_async([](mavlink_message_t& msg){
- // //qDebug()<<"Intercept:send message"<get_system_id()==OHD_SYS_ID_AIR){
- qDebug()<<"Found OHD AIR station";
- systemOhdAir=system;
- MavlinkSettingsModel::instanceAir().set_param_client(system);
- MavlinkSettingsModel::instanceAirCamera().set_param_client(system);
- MavlinkSettingsModel::instanceAirCamera2().set_param_client(system);
- AOHDSystem::instanceAir().set_system(system);
- // hacky, for connecting to the air unit directly
- if(passtroughOhdGround==nullptr){
- passtroughOhdGround=std::make_shared(system);
- passtroughOhdGround->intercept_incoming_messages_async([this](mavlink_message_t& msg){
- //qDebug()<<"Intercept:Got message"<has_autopilot()){
- else {
- qDebug()<<"Got system id: "<<(int)system->get_system_id()<<" components:"<component_ids()).c_str();
- // By default, we assume there is one additional non-openhd system - the FC
- bool is_fc=true;
- QSettings settings;
- const bool dirty_enable_mavlink_fc_sys_id_check=settings.value("dirty_enable_mavlink_fc_sys_id_check",false).toBool();
- if(dirty_enable_mavlink_fc_sys_id_check){
- // filtering, default off
- const auto comp_ids=system->component_ids();
- is_fc=mavsdk::helper::any_comp_id_autopilot(comp_ids);
- }
- if(is_fc){
- qDebug()<<"Found FC";
- // we got the flight controller
- FCMavlinkSystem::instance().set_system(system);
- // hacky, for SITL testing
- if(passtroughOhdGround==nullptr){
- passtroughOhdGround=std::make_shared(system);
- passtroughOhdGround->intercept_incoming_messages_async([this](mavlink_message_t& msg){
- //qDebug()<<"Intercept:Got message"<get_system_id();
- }
- //MavlinkSettingsModel::instanceFC().set_param_client(system);
+ QSettings settings;
+ const bool dev_use_tcp = settings.value("dev_mavlink_via_tcp",false).toBool();
+ if(dev_use_tcp){
+ // TODO
+ }else{
+ // default, udp, passive (like QGC)
+ auto cb_udp=[this](mavlink_message_t msg){
+ process_mavlink_message(msg);
+ };
+ const auto ip="0.0.0.0"; //"127.0.0.1"
+ m_udp_connection=std::make_unique(ip,QOPENHD_GROUND_CLIENT_UDP_PORT_IN,cb_udp);
+ m_udp_connection->start();
}
}
@@ -163,192 +49,221 @@ bool MavlinkTelemetry::sendMessage(mavlink_message_t msg){
// probably a programming error, the message was not packed with the right comp id
qDebug()<<"WARN Sending message with comp id:"< lock(systems_mutex);
- if(passtroughOhdGround!=nullptr){
- passtroughOhdGround->send_message(msg);
+ if(m_udp_connection){
+ m_udp_connection->send_message(msg);
return true;
}else{
- // If the passtrough is not created yet, a connection to the OHD ground unit has not yet been established.
- //qDebug()<<"MAVSDK passtroughOhdGround not created";
- // only log it once, then not again to keep logcat clean
- static bool first=true;
- if(first){
- qDebug()<<"No OHD Ground unit connected";
- //first=false;
+ if(m_tcp_connection){
+ m_tcp_connection->send_message(msg);
+ return true;
}
}
return false;
}
-static int get_message_size(const mavlink_message_t msg){
+static int get_message_size(const mavlink_message_t& msg){
return sizeof(msg);
}
-void MavlinkTelemetry::onProcessMavlinkMessage(mavlink_message_t msg)
+void MavlinkTelemetry::process_mavlink_message(const mavlink_message_t& msg)
{
m_tele_received_packets++;
m_tele_received_bytes+=get_message_size(msg);
set_telemetry_pps_in(m_tele_pps_in.get_last_or_recalculate(m_tele_received_packets));
set_telemetry_bps_in(m_tele_bitrate_in.get_last_or_recalculate(m_tele_received_bytes));
//qDebug()<<"MavlinkTelemetry::onProcessMavlinkMessage"<component_ids();
+ //is_fc=mavsdk::helper::any_comp_id_autopilot(comp_ids);
+ }
+ if(is_fc){
+ qDebug()<<"Found FC";
+ // we got the flight controller
+ FCMavlinkSystem::instance().set_system_id(source_sysid);
+ m_fc_sys_id=source_sysid;
+ m_fc_comp_id=source_compid;
+ m_fc_found=true;
+ }else{
+ qDebug()<<"Got weird system:"<check_acknowledgement(msg);
- auto opt_command=m_msg_interval_helper->create_command_if_needed();
- if(opt_command.has_value()){
- auto command=opt_command.value();
- send_command_long_oneshot(command);
- }
- }
+ process_broadcast_message_fc(msg);
+ FCMsgIntervalHandler::instance().opt_send_messages();
+ FCMissionHandler::instance().opt_send_messages();
}else{
qDebug()<<"MavlinkTelemetry received unmatched message "<std::chrono::seconds(1)){
- m_last_time_version_requested=std::chrono::steady_clock::now();
- if(AOHDSystem::instanceAir().should_request_version() || AOHDSystem::instanceGround().should_request_version()){
- request_openhd_version();
- }
- }*/
}
-void MavlinkTelemetry::tcp_only_establish_connection()
+void MavlinkTelemetry::process_broadcast_message_openhd_air(const mavlink_message_t &msg)
{
- assert(dev_use_tcp);
- qDebug()<<"tcp_only_establish_connection";
- while(true){
- {
- std::stringstream ss;
- ss<<"TCP try connecting to ["<add_tcp_connection(dev_tcp_server_ip,OHD_GROUND_SERVER_TCP_PORT);
- std::stringstream ss;
- ss<<"MAVSDK TCP connection result: " << connection_result;
- qDebug()<(ip.toStdString(),QOPENHD_OPENHD_GROUND_TCP_SERVER_PORT,cb_tcp);
+ m_tcp_connection->start();
}
-void MavlinkTelemetry::request_openhd_version()
+void MavlinkTelemetry::enable_udp()
{
- mavlink_command_long_t command{};
- command.command=MAV_CMD_REQUEST_MESSAGE;
- command.param1=static_cast(MAVLINK_MSG_ID_OPENHD_VERSION_MESSAGE);
- send_command_long_oneshot(command);
+ m_tcp_connection=nullptr;
+ m_udp_connection=nullptr;
+ // default, udp, passive (like QGC)
+ auto cb_udp=[this](mavlink_message_t msg){
+ process_mavlink_message(msg);
+ };
+ const auto ip="0.0.0.0"; //"127.0.0.1"
+ m_udp_connection=std::make_unique(ip,QOPENHD_GROUND_CLIENT_UDP_PORT_IN,cb_udp);
+ m_udp_connection->start();
}
-bool MavlinkTelemetry::send_command_long_oneshot(const mavlink_command_long_t &command)
+void MavlinkTelemetry::ping_all_systems()
{
mavlink_message_t msg;
- mavlink_msg_command_long_encode(QOpenHDMavlinkHelper::get_own_sys_id(),QOpenHDMavlinkHelper::get_own_comp_id(), &msg,&command);
- return sendMessage(msg);
+ mavlink_timesync_t timesync{};
+ timesync.tc1=0;
+ // Ardupilot seems to use us
+ m_last_timesync_out_us=QOpenHDMavlinkHelper::getTimeMicroseconds();
+ timesync.ts1=m_last_timesync_out_us;
+ mavlink_msg_timesync_encode(QOpenHDMavlinkHelper::get_own_sys_id(),QOpenHDMavlinkHelper::get_own_comp_id(),&msg,×ync);
+ sendMessage(msg);
}
-bool MavlinkTelemetry::ohd_gnd_request_channel_scan(int freq_bands,int channel_widths)
+MavlinkTelemetry::FCMavId MavlinkTelemetry::get_fc_mav_id()
{
- qDebug()<<"Channels can: "<(freq_bands);
- command.param2=static_cast(channel_widths);
- return send_command_long_oneshot(command);*/
- if(passtroughOhdGround){
- mavsdk::MavlinkPassthrough::CommandLong command{};
- command.target_sysid=OHD_SYS_ID_GROUND;
- command.target_compid=OHD_COMP_ID_LINK_PARAM;
- command.command=OPENHD_CMD_INITIATE_CHANNEL_SEARCH;
- command.param1=static_cast(freq_bands);
- command.param2=static_cast(channel_widths);
- auto res=passtroughOhdGround->send_command_long(command);
- return res==mavsdk::MavlinkPassthrough::Result::Success;
+ if(m_fc_found){
+ return {m_fc_sys_id,m_fc_comp_id};
}
- return false;
+ return {1,MAV_COMP_ID_AUTOPILOT1};
}
void MavlinkTelemetry::re_apply_rates()
{
- if(m_msg_interval_helper){
- m_msg_interval_helper->restart();
- }
+ FCMsgIntervalHandler::instance().restart();
}
diff --git a/app/telemetry/MavlinkTelemetry.h b/app/telemetry/MavlinkTelemetry.h
index 011ce2c1a..c2ab97e9d 100644
--- a/app/telemetry/MavlinkTelemetry.h
+++ b/app/telemetry/MavlinkTelemetry.h
@@ -7,21 +7,23 @@
#include
#include
-#include "mavsdk_include.h"
-#include "models/fcmessageintervalhelper.hpp"
+#include "util/mavlink_include.h"
#include "../../lib/lqtutils_master/lqtutils_prop.h"
#include "../common/TimeHelper.hpp"
+#include "connection/udp_connection.h"
+#include "connection/tcp_connection.h"
+
/**
- * Changed: Used to have custom UDP and TCP stuff, but now just uses MAVSDK - MAVSDK already has both TCP and UDP support.
*
- * @brief This is the one and only (mavlink telemetry) connection of QOpenHD to OpenHD
- * (More specific, the OpenHD Ground Station - but since the Ground station forwards messages to the air pi,
+ * @brief Main entry / exit point for all mavlink telemetry
+ * (More specific, to / from the OpenHD Ground Station - but since the Ground station forwards messages to/from the air pi,
* one can indirectly also reach the air pi via the ground pi, as well as the mavlink FC connected to the air pi).
* Its functionalities are simple:
+ * 1) "Connecting to the ground unit (either UDP or TCP)"
* 1) sending mavlink messages to OpenHD
* 2) receiving mavlink messages from OpenHD
- * 3) Handling the mavsdk "system discovery" for our OpenHD mavlink network, which is defined by
+ * 3) Handling the "system discovery" for our OpenHD mavlink network, which is defined by
* a) OHD Air unit (own sys id)
* b) OHD Ground unit (own sys id)
* c) Optional FC connected to the air unit
@@ -32,8 +34,7 @@ class MavlinkTelemetry : public QObject
public:
MavlinkTelemetry(QObject *parent = nullptr);
static MavlinkTelemetry& instance();
- // Called in main.cpp such that we can call the couple of Q_INVOCABLE methods
- static void register_for_qml(QQmlContext* qml_context);
+ void start();
/**
* Send a message to the OHD ground unit. If no connection has been established (yet), this should return immediately.
* The message can be aimed at either the OHD ground unit, the OHD air unit (forwarded by OpenHD) or the FC connected to the
@@ -42,66 +43,50 @@ class MavlinkTelemetry : public QObject
* @return true on success (this does not mean the message was received, but rather the message was sent out via the lossy connection)
*/
bool sendMessage(mavlink_message_t msg);
+ struct FCMavId{
+ int comp_id;
+ int sys_id;
+ };
+ // Returns default FC sys / comp id until FC is successfully discovered.
+ FCMavId get_fc_mav_id();
+public:
+ // ping all the systems (using timesync, since "ping" is deprecated)
+ Q_INVOKABLE void ping_all_systems();
+ // re-apply all FC telemetry rate(s)
+ Q_INVOKABLE void re_apply_rates();
+ // Switch from UDP to TCP
+ Q_INVOKABLE void add_tcp_connection_handler(QString ip);
+ // Back to udp
+ Q_INVOKABLE void enable_udp();
+public:
// A couple of stats exposed as QT properties
L_RO_PROP(int,telemetry_pps_in,set_telemetry_pps_in,-1)
L_RO_PROP(int,telemetry_bps_in,set_telemetry_bps_in,-1)
+ //
private:
// We follow the same practice as QGrouncontroll: Listen for incoming data on a specific UDP port,
// -> as soon as we got the first packet, we know the address to send data to for bidirectional communication
static constexpr auto QOPENHD_GROUND_CLIENT_UDP_PORT_IN=14550;
- // change requires restart, udp is used by default (not tcp)
- bool dev_use_tcp=false;
- std::string dev_tcp_server_ip="0.0.0.0";
- // workaround systems discovery is not thread safe
- std::mutex systems_mutex;
- int mavsdk_already_known_systems=0;
- std::shared_ptr mavsdk=nullptr;
- std::shared_ptr systemOhdGround=nullptr;
- std::shared_ptr systemOhdAir=nullptr;
- // MAVSDK is a bit stupid in this direction - passtrough(s) are for each system, but if there are multiple
- // system(s) behind a connection, this pattern is completely broken.
- // Normally, this passtrough is for the ground station - since we normally talk to both air and fc via the ground
- // However, if there is no ground, we create the passtrough from the air or FC system too.
- // This way one can also connect qopenhd to the FC without air / ground running and/or to the air unit without ground.
- std::shared_ptr passtroughOhdGround=nullptr;
- // called by mavsdk whenever a new system is detected
- void onNewSystem(std::shared_ptr system);
- // Called every time we get a mavlink message (from any system). Intended to be used for message types that don't
- // work with mavsdk / their subscription based pattern.
- void onProcessMavlinkMessage(mavlink_message_t msg);
- // The mavsdk tcp connect does block, we therefore need to do it in its own thread
- // (not block the UI thread)
- void tcp_only_establish_connection();
- std::unique_ptr m_tcp_connect_thread= nullptr;
+ static constexpr auto QOPENHD_OPENHD_GROUND_TCP_SERVER_PORT=5760;
+ // Called every time we get a mavlink message (from any system).
+ void process_mavlink_message(const mavlink_message_t& msg);
+ void process_broadcast_message_openhd_air(const mavlink_message_t& msg);
+ void process_broadcast_message_openhd_gnd(const mavlink_message_t& msg);
+ void process_broadcast_message_fc(const mavlink_message_t& msg);
+ // timesync is handled extra independently
+ void process_message_timesync(const mavlink_message_t &msg);
+private:
+ std::unique_ptr m_udp_connection=nullptr;
+ std::unique_ptr m_tcp_connection=nullptr;
+ int64_t m_last_timesync_out_us=0;
+ bool m_fc_found=false;
+ int m_fc_sys_id=-1;
+ int m_fc_comp_id=-1;
+ // For calculating input pps / bps
int64_t m_tele_received_bytes=0;
int64_t m_tele_received_packets=0;
BitrateCalculator2 m_tele_bitrate_in;
PacketsPerSecondCalculator m_tele_pps_in;
-public:
- // ping all the systems (using timesync, since "ping" is deprecated)
- Q_INVOKABLE void ping_all_systems();
- // request the OpenHD version, both OpenHD air and ground unit will respond to that message.
- Q_INVOKABLE void request_openhd_version();
- // send a command, to all connected systems
- // doesn't reatransmitt
- bool send_command_long_oneshot(const mavlink_command_long_t& command);
-private:
- int pingSequenceNumber=0;
- int64_t lastTimeSyncOut=0;
-private:
- std::chrono::steady_clock::time_point m_last_time_version_requested=std::chrono::steady_clock::now();
-public:
- // freq_bands:
- // 0: 2.4G and 5.8G
- // 1: 2.4G only
- // 2: 5.8G only
- // similar for channel widths
- Q_INVOKABLE bool ohd_gnd_request_channel_scan(int freq_bands,int channel_widths);
-private:
- std::unique_ptr m_msg_interval_helper=nullptr;
- void process_check_for_data_rates(const mavlink_message_t &msg);
-public:
- Q_INVOKABLE void re_apply_rates();
};
#endif // OHDMAVLINKCONNECTION_H
diff --git a/app/telemetry/action/README.md b/app/telemetry/action/README.md
new file mode 100644
index 000000000..9e1928b54
--- /dev/null
+++ b/app/telemetry/action/README.md
@@ -0,0 +1,4 @@
+Here we have code where qopenhd needs to actively talk to a mavlink system,
+aka the FC, the openhd air unit or the openhd ground unit.
+
+(additionally to param / settings, which are in a different directory due to their complexity)
diff --git a/app/telemetry/action/create_cmd_helper.hpp b/app/telemetry/action/create_cmd_helper.hpp
new file mode 100644
index 000000000..b383a45df
--- /dev/null
+++ b/app/telemetry/action/create_cmd_helper.hpp
@@ -0,0 +1,73 @@
+#ifndef CMD_HELPER_H
+#define CMD_HELPER_H
+
+#include "../util/mavlink_include.h"
+
+// Here we have various util methods to create mavlink_command_long_t commands
+namespace cmd::helper{
+
+static mavlink_command_long_t create_cmd_reboot(int target_sysid,int target_compid,bool reboot){
+ mavlink_command_long_t cmd{};
+ cmd.target_system=target_sysid;
+ cmd.target_component=target_compid;
+ cmd.command=MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN;
+ cmd.param1=0;
+ cmd.param2=(reboot ? 1 : 2);
+ return cmd;
+}
+
+static mavlink_command_long_t create_cmd_request_message(int target_sysid,int target_compid,int message_id){
+ mavlink_command_long_t command{};
+ command.command=MAV_CMD_REQUEST_MESSAGE;
+ command.target_system=target_sysid;
+ command.target_component=target_compid;
+ command.param1=static_cast(message_id);
+ return command;
+}
+
+static mavlink_command_long_t create_cmd_request_openhd_version(int target_sysid,int target_compid){
+ return create_cmd_request_message(target_sysid,target_compid,MAVLINK_MSG_ID_OPENHD_VERSION_MESSAGE);
+}
+
+static mavlink_command_long_t create_cmd_arm(int fc_sys_id,int fc_comp_id,bool arm){
+ mavlink_command_long_t cmd{};
+ cmd.command=MAV_CMD_COMPONENT_ARM_DISARM;
+ cmd.target_system=fc_sys_id;
+ cmd.target_component=fc_comp_id;
+ //cmd.confirmation=false;
+ cmd.param1=arm ? 1 : 0;
+ cmd.param2=0; // do not force
+ return cmd;
+}
+
+static mavlink_command_long_t create_cmd_do_set_flight_mode(int fc_sys_id,int fc_comp_id,int mode){
+ mavlink_command_long_t cmd{};
+ cmd.command = MAV_CMD_DO_SET_MODE;
+
+ cmd.target_system= fc_sys_id;
+ cmd.target_component=fc_comp_id;
+
+ cmd.param1=MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
+ cmd.param2=mode;
+ cmd.param3=0;
+ cmd.param4=0;
+ cmd.param5=0;
+ cmd.param6=0;
+ cmd.param7=0;
+ return cmd;
+}
+
+static mavlink_command_long_t create_cmd_set_msg_interval(int target_system,int target_component,int msg_type,int interval_us){
+ mavlink_command_long_t command{};
+ command.target_system=target_system;
+ command.target_component=target_component;
+ command.command=MAV_CMD_SET_MESSAGE_INTERVAL;
+ command.confirmation=0;
+ command.param1=msg_type;
+ command.param2=interval_us;
+ return command;
+}
+
+}
+
+#endif // CMD_HELPER_H
diff --git a/app/telemetry/action/fcaction.cpp b/app/telemetry/action/fcaction.cpp
new file mode 100644
index 000000000..140878d87
--- /dev/null
+++ b/app/telemetry/action/fcaction.cpp
@@ -0,0 +1,183 @@
+#include "fcaction.h"
+#include "qdebug.h"
+
+#include "../../logging/hudlogmessagesmodel.h"
+#include "../MavlinkTelemetry.h"
+#include "impl/cmdsender.h"
+
+#include "create_cmd_helper.hpp"
+#include "../models/fcmavlinksystem.h"
+#include "util/mavlink_enum_to_string.h"
+
+FCAction::FCAction(QObject *parent)
+ : QObject{parent}
+{
+
+}
+
+FCAction &FCAction::instance()
+{
+ static FCAction instance;
+ return instance;
+}
+
+void FCAction::arm_fc_async(bool arm)
+{
+ if(!FCMavlinkSystem::instance().is_alive()){
+ HUDLogMessagesModel::instance().add_message_info("FC not alive");
+ return;
+ }
+ const auto fc_id=MavlinkTelemetry::instance().get_fc_mav_id();
+ const auto command=cmd::helper::create_cmd_arm(fc_id.sys_id,fc_id.comp_id,arm);
+ auto cb=[this,arm](CmdSender::RunCommandResult result){
+ if(!result.opt_ack.has_value()){
+ HUDLogMessagesModel::instance().add_message_info(arm ? "ARM - FC not reachable" : "DISARM - FC not reachable");
+ }else if(result.is_accepted()){
+ HUDLogMessagesModel::instance().add_message_info(arm ? "ARMED FC":"DISARMED FC");
+ }else{
+ HUDLogMessagesModel::instance().add_message_info(arm ? "ARM not possible":"DISARM not possible");
+ }
+ };
+ CmdSender::instance().send_command_long_async(command,cb);
+}
+
+void FCAction::flight_mode_cmd_async(long cmd_msg) {
+ if(cmd_msg<0){
+ // We get the flight mode command from qml, something is wrong with it
+ std::stringstream ss;
+ ss<<"Invalid FM "< create_fm_mapping(){
+ std::map ret;
+ ret["RTL"]=XFlightMode{COPTER_MODE_RTL,PLANE_MODE_RTL};
+ ret["STABILIZE"]=XFlightMode{COPTER_MODE_STABILIZE,PLANE_MODE_STABILIZE};
+ ret["LOITER"]=XFlightMode{COPTER_MODE_LOITER,PLANE_MODE_LOITER};
+ ret["CIRCLE"]=XFlightMode{COPTER_MODE_CIRCLE,PLANE_MODE_CIRCLE};
+ ret["AUTO"]=XFlightMode{COPTER_MODE_AUTO,PLANE_MODE_AUTO};
+ ret["AUTOTUNE"]=XFlightMode{COPTER_MODE_AUTOTUNE,PLANE_MODE_AUTOTUNE};
+ ret["MANUAL"]=XFlightMode{-1,PLANE_MODE_MANUAL};
+ ret["FBWA"]=XFlightMode{-1,PLANE_MODE_FLY_BY_WIRE_A};
+ ret["FBWB"]=XFlightMode{-1,PLANE_MODE_FLY_BY_WIRE_B};
+ ret["QSTABILIZE"]=XFlightMode{-1,PLANE_MODE_QSTABILIZE};
+ ret["QHOVER"]=XFlightMode{-1,PLANE_MODE_QHOVER};
+ ret["QLOITER"]=XFlightMode{-1,PLANE_MODE_QLOITER};
+ ret["QLAND"]=XFlightMode{-1,PLANE_MODE_QLAND};
+ ret["QRTL"]=XFlightMode{-1,PLANE_MODE_QRTL};
+ ret["ALT_HOLD"]=XFlightMode{COPTER_MODE_ALT_HOLD,-1};
+ ret["POS_HOLD"]=XFlightMode{COPTER_MODE_POSHOLD,-1};
+ ret["ACRO"]=XFlightMode{COPTER_MODE_ACRO,PLANE_MODE_ACRO};
+
+ ret["GUIDED"]=XFlightMode{COPTER_MODE_GUIDED,PLANE_MODE_GUIDED};
+ // (weird) copter only mode(s)
+ ret["LAND"]=XFlightMode{COPTER_MODE_LAND,-1};
+ ret["SMART_RTL"]=XFlightMode{COPTER_MODE_SMART_RTL,-1};
+ ret["ZIGZAG"]=XFlightMode{COPTER_MODE_ZIGZAG,-1};
+ ret["AUTO_RTL"]=XFlightMode{COPTER_MODE_AUTO_RTL,-1};
+ // (weird) plane only mode(s)
+ ret["CRUISE"]=XFlightMode{-1,PLANE_MODE_CRUISE};
+ ret["TAKEOFF"]=XFlightMode{-1,PLANE_MODE_TAKEOFF};
+ //ret[""]=XFlightMode{COPTER_MODE_,PLANE_MODE_};
+
+ return ret;
+}
+
+static int flight_mode_string_to_int(const std::string& flight_mode,const int mav_type){
+ if(mav_type<0){
+ // mav type not yet known
+ return -1;
+ }
+ const auto fm_map=create_fm_mapping();
+ if(fm_map.find(flight_mode)!=fm_map.end()){
+ // mapped
+ const XFlightMode& x_fm=fm_map.at(flight_mode);
+ if(qopenhd::flight_mode_is_copter((MAV_TYPE)mav_type)){
+ return x_fm.id_copter;
+ }else if(qopenhd::flight_mode_is_plane((MAV_TYPE)mav_type)){
+ return x_fm.id_plane;
+ }else{
+ qDebug()<<"FM mapped not to this mav type:"<<(int)mav_type;
+ }
+ }else{
+ qDebug()<<"FM unmapped:"<=0){
+ flight_mode_cmd_async(flight_mode_type);
+ }else{
+ HUDLogMessagesModel::instance().add_message_warning("Invalid flight mode");
+ }
+}
+
+bool FCAction::has_mapping(QString flight_mode)
+{
+ int mapping=flight_mode_string_to_int(flight_mode.toStdString(),m_ardupilot_mav_type);
+ if(mapping>=0)return true;
+ return false;
+}
+
+void FCAction::request_home_position_from_fc()
+{
+ const auto fc_id=MavlinkTelemetry::instance().get_fc_mav_id();
+ const auto command=cmd::helper::create_cmd_request_message(fc_id.sys_id,fc_id.comp_id,MAVLINK_MSG_ID_HOME_POSITION);
+ const auto result=CmdSender::instance().send_command_long_blocking(command);
+ if(result==CmdSender::CMD_SUCCESS){
+ HUDLogMessagesModel::instance().add_message_info("Request home success");
+ }else{
+ HUDLogMessagesModel::instance().add_message_info("Request home failure");
+ }
+}
+
+bool FCAction::send_command_reboot(bool reboot)
+{
+ const auto fc_id=MavlinkTelemetry::instance().get_fc_mav_id();
+ auto command=cmd::helper::create_cmd_reboot(fc_id.sys_id,fc_id.comp_id,reboot);
+ const auto res=CmdSender::instance().send_command_long_blocking(command);
+ return res==CmdSender::Result::CMD_SUCCESS;
+}
diff --git a/app/telemetry/action/fcaction.h b/app/telemetry/action/fcaction.h
new file mode 100644
index 000000000..430a94098
--- /dev/null
+++ b/app/telemetry/action/fcaction.h
@@ -0,0 +1,52 @@
+#ifndef FCACTION_H
+#define FCACTION_H
+
+#include
+#include
+
+#include "../util/mavlink_include.h"
+#include "../../../lib/lqtutils_master/lqtutils_prop.h"
+
+/**
+ * This is the one and only class from which messages / actions can be sent to the FC.
+ * THE REST IS BROADCAST !
+ */
+class FCAction : public QObject
+{
+ Q_OBJECT
+public:
+ explicit FCAction(QObject *parent = nullptr);
+ static FCAction& instance();
+public:
+ L_RO_PROP(int,ardupilot_mav_type,set_ardupilot_mav_type,-1);
+public:
+ // WARNING: Do not call any non-async send command methods from the same thread that is parsing the mavlink messages !
+ //
+ // Try to change the arming state.
+ // The result (success/failure) is logged in the HUD once completed
+ Q_INVOKABLE void arm_fc_async(bool arm=false);
+
+ // Sends a command to change the flight mode. Note that this is more complicated than it sounds at first,
+ // since copter and plane for example do have different flight mode enums.
+ // This function is async to not block the calling UI - the result is logged to the HUDLogMessageModel
+ // also, this method only allows one flight mode change queued up at a time
+ Q_INVOKABLE void flight_mode_cmd_async(long cmd_msg);
+ // FUCKING ANNOYING / DANGEROUS:
+ // The mapping of flight modes is completely different for copter/plane/...
+ // If we haven't mapped a (unique) flight mode string to the appropriate COPTER_, PLANE_ command
+ // we just log a warning and return.
+ Q_INVOKABLE void flight_mode_cmd_async_string(QString flight_mode);
+ // Returns true if we have a mapping for this flight mode (string id)
+ // taking the current mav type (copter, plane, ..) int account.
+ // This method is called from qml to only show FLightModeSlider elements that will work for the given mav type
+ Q_INVOKABLE bool has_mapping(QString flight_mode);
+
+ // Some FC stop sending home position when armed, re-request the home position
+ Q_INVOKABLE void request_home_position_from_fc();
+
+ Q_INVOKABLE bool send_command_reboot(bool reboot);
+private:
+ std::atomic m_has_currently_runnning_flight_mode_change=false;
+};
+
+#endif // FCACTION_H
diff --git a/app/telemetry/action/fcmissionhandler.cpp b/app/telemetry/action/fcmissionhandler.cpp
new file mode 100644
index 000000000..709a99260
--- /dev/null
+++ b/app/telemetry/action/fcmissionhandler.cpp
@@ -0,0 +1,226 @@
+#include "fcmissionhandler.h"
+#include "../util/qopenhdmavlinkhelper.hpp"
+#include "../util/telemetryutil.hpp"
+#include "../MavlinkTelemetry.h"
+
+#include "../models/fcmavlinkmissionitemsmodel.h"
+
+FCMissionHandler::FCMissionHandler(QObject *parent): QObject(parent)
+{
+ m_mission_items.reserve(MAX_N_MISSION_ITEMS);
+ m_missing_items.reserve(MAX_N_MISSION_ITEMS);
+}
+
+FCMissionHandler &FCMissionHandler::instance()
+{
+ static FCMissionHandler instance;
+ return instance;
+}
+
+bool FCMissionHandler::process_message(const mavlink_message_t &msg)
+{
+ bool consumed=false;
+ switch(msg.msgid){
+ case MAVLINK_MSG_ID_MISSION_CURRENT:{
+ // https://mavlink.io/en/messages/common.html#MISSION_CURRENT
+ mavlink_mission_current_t mission_current;
+ mavlink_msg_mission_current_decode(&msg,&mission_current);
+ update_mission_current(mission_current);
+ consumed=true;
+ break;
+ }
+ case MAVLINK_MSG_ID_MISSION_COUNT:{
+ //qDebug()<<"Got MAVLINK_MSG_ID_MISSION_COUNT";
+ // https://mavlink.io/en/messages/common.html#MISSION_COUNT
+ mavlink_mission_count_t mission;
+ mavlink_msg_mission_count_decode(&msg,&mission);
+ update_mission_count(mission);
+ consumed=true;
+ break;
+ }
+ case MAVLINK_MSG_ID_MISSION_ITEM_INT:{
+ mavlink_mission_item_int_t item;
+ mavlink_msg_mission_item_int_decode(&msg, &item);
+ update_mission(item);
+ consumed=true;
+ break;
+ }
+ }
+ return consumed;
+}
+
+static mavlink_mission_request_list_t create_request_mission_count(int fc_sys_id,int fc_comp_id){
+ mavlink_mission_request_list_t command{};
+ command.mission_type=MAV_MISSION_TYPE_MISSION;
+ command.target_system=fc_sys_id;
+ command.target_component=fc_comp_id;
+ return command;
+}
+
+static mavlink_message_t create_request_mission_count_msg(int fc_sys_id,int fc_comp_id){
+ const auto tmp=create_request_mission_count(fc_sys_id,fc_comp_id);
+ mavlink_message_t message;
+ const auto sys_id=QOpenHDMavlinkHelper::get_own_sys_id();
+ const auto comp_id=QOpenHDMavlinkHelper::get_own_comp_id();
+ mavlink_msg_mission_request_list_encode(sys_id,comp_id,&message,&tmp);
+ return message;
+}
+static mavlink_message_t create_request_mission_msg(int fc_sys_id,int fc_comp_id,int sequence){
+ mavlink_mission_request_int_t request{};
+ request.mission_type=MAV_MISSION_TYPE_MISSION;
+ request.target_system=fc_sys_id;
+ request.target_component=fc_comp_id;
+ request.seq=sequence;
+ mavlink_message_t message;
+ const auto sys_id=QOpenHDMavlinkHelper::get_own_sys_id();
+ const auto comp_id=QOpenHDMavlinkHelper::get_own_comp_id();
+ mavlink_msg_mission_request_int_encode(sys_id,comp_id,&message,&request);
+ return message;
+}
+
+void FCMissionHandler::opt_send_messages()
+{
+ std::lock_guard lock(m_mutex);
+ if(!m_has_mission_count){
+ set_current_status("Requesting");
+ const auto elapsed=std::chrono::steady_clock::now()-m_last_count_request;
+ if(elapsed>std::chrono::seconds(1)){
+ m_last_count_request=std::chrono::steady_clock::now();
+ const auto fc_id=MavlinkTelemetry::instance().get_fc_mav_id();
+ auto message=create_request_mission_count_msg(fc_id.sys_id,fc_id.comp_id);
+ MavlinkTelemetry::instance().sendMessage(message);
+ //qDebug()<<"Requested";
+ }
+ return;
+ }
+ // check if we are missing missions
+ if(m_missing_items.empty()){
+ std::stringstream ss;
+ ss<<"Done, total:"<std::chrono::seconds(1)){
+ m_last_item_request=std::chrono::steady_clock::now();
+ const auto missing_missions=m_missing_items.size();
+ //qDebug()<<"Missions missing: "< lock(m_mutex);
+ m_mission_items.resize(0);
+ m_missing_items.resize(0);
+ m_has_mission_count=false;
+ FCMavlinkMissionItemsModel::instance().p_initialize(0);
+}
+
+void FCMissionHandler::update_mission_count(const mavlink_mission_count_t& mission_count)
+{
+ //qDebug()<<"Got MAVLINK_MSG_ID_MISSION_COUNT total:"< lock(m_mutex);
+ if(count==m_mission_items.size()){
+ qDebug()<<"Same size";
+ if(count==0){
+ m_has_mission_count=true;
+ }
+ return;
+ }
+ qDebug()<<"Mission count changed from "<(mission_item.x)* 1e-7;
+ const double lon=static_cast(mission_item.y)* 1e-7;
+ /*if(lat==0.0 || lon==0.0){
+ qDebug()<<"invalid mission item - invalid lat/lon"< lock(m_mutex);
+ if(! (mission_seq>=0 && mission_seq lock(m_mutex);
+ if(!(current_mission>=0 && current_mission<=m_mission_items.size())){
+ qDebug()<<"Invalid current mission "<
+#include
+#include