diff --git a/.appveyor.yml b/.appveyor.yml
index 279b1d44d..f6d578dce 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -81,7 +81,7 @@ for:
qml-module-qtlocation qml-module-qtpositioning qml-module-qtquick-window2 qml-module-qtquick-dialogs \
qml-module-qtquick-controls qml-module-qtquick-layouts \
libqt5serialport5-dev qtdeclarative5-dev qtpositioning5-dev qtlocation5-dev \
- libqt5charts5-dev \
+ libqt5charts5-dev libqt5texttospeech5-dev \
libusb-1.0-0-dev libboost-all-dev libasound2-dev libopencv-dev libopencv-imgcodecs-dev \
libxml2-dev bison flex ffmpeg libpostproc-dev libavcodec-dev libavformat-dev \
libopus-dev libcodec2-dev libairspy-dev libhackrf-dev \
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9623bb869..d315509b3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -312,7 +312,8 @@ if (BUILD_GUI)
QuickWidgets
Positioning
Location
- Charts)
+ Charts
+ TextToSpeech)
endif()
# other requirements
@@ -366,6 +367,8 @@ else()
find_package(LibMbe)
find_package(SerialDV REQUIRED)
find_package(LibDSDcc)
+ find_package(Sgp4)
+ find_package(AptDec)
endif()
# Devices
diff --git a/cmake/Modules/FindAptDec.cmake b/cmake/Modules/FindAptDec.cmake
new file mode 100644
index 000000000..5443a4f1f
--- /dev/null
+++ b/cmake/Modules/FindAptDec.cmake
@@ -0,0 +1,29 @@
+IF(NOT APT_FOUND)
+ INCLUDE(FindPkgConfig)
+ PKG_CHECK_MODULES(PC_APT apt)
+
+ FIND_PATH(
+ APT_INCLUDE_DIR
+ NAMES apt.h
+ HINTS ${APT_DIR}/include/apt
+ PATHS /usr/local/include/apt
+ /usr/include/apt
+ )
+
+ FIND_LIBRARY(
+ APT_LIBRARIES
+ NAMES apt
+ HINTS ${APT_DIR}/lib
+ PATHS /usr/local/lib
+ /usr/lib
+ /usr/lib64
+ )
+
+ message(STATUS "APT LIBRARIES " ${APT_LIBRARIES})
+ message(STATUS "APT INCLUDE DIRS " ${APT_INCLUDE_DIR})
+
+ INCLUDE(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(APT DEFAULT_MSG APT_LIBRARIES APT_INCLUDE_DIR)
+ MARK_AS_ADVANCED(APT_LIBRARIES APT_INCLUDE_DIR)
+
+ENDIF(NOT APT_FOUND)
diff --git a/cmake/Modules/FindSgp4.cmake b/cmake/Modules/FindSgp4.cmake
new file mode 100644
index 000000000..96dfbc713
--- /dev/null
+++ b/cmake/Modules/FindSgp4.cmake
@@ -0,0 +1,29 @@
+IF(NOT SGP4_FOUND)
+ INCLUDE(FindPkgConfig)
+ PKG_CHECK_MODULES(PC_SGP4 sgp4)
+
+ FIND_PATH(
+ SGP4_INCLUDE_DIR
+ NAMES SGP4.h
+ HINTS ${SGP4_DIR}/include/SGP4
+ PATHS /usr/local/include/SGP4
+ /usr/include/SGP4
+ )
+
+ FIND_LIBRARY(
+ SGP4_LIBRARIES
+ NAMES sgp4s
+ HINTS ${SGP4_DIR}/lib
+ PATHS /usr/local/lib
+ /usr/lib
+ /usr/lib64
+ )
+
+ message(STATUS "SGP4 LIBRARIES " ${SGP4_LIBRARIES})
+ message(STATUS "SGP4 INCLUDE DIRS " ${SGP4_INCLUDE_DIR})
+
+ INCLUDE(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(SGP4 DEFAULT_MSG SGP4_LIBRARIES SGP4_INCLUDE_DIR)
+ MARK_AS_ADVANCED(SGP4_LIBRARIES SGP4_INCLUDE_DIR)
+
+ENDIF(NOT SGP4_FOUND)
diff --git a/debian/control b/debian/control
index dfdfce52a..403317b13 100644
--- a/debian/control
+++ b/debian/control
@@ -22,6 +22,7 @@ Build-Depends: debhelper (>= 9),
qml-module-qtquick-layouts,
libqt5serialport5-dev,
libqt5charts5-dev,
+ libqt5texttospeech5-dev,
qtdeclarative5-dev,
qtpositioning5-dev,
qtlocation5-dev,
diff --git a/doc/img/APTDemod_plugin.png b/doc/img/APTDemod_plugin.png
new file mode 100644
index 000000000..24d98125b
Binary files /dev/null and b/doc/img/APTDemod_plugin.png differ
diff --git a/doc/img/APTDemod_plugin_settings.png b/doc/img/APTDemod_plugin_settings.png
new file mode 100644
index 000000000..5934b4e54
Binary files /dev/null and b/doc/img/APTDemod_plugin_settings.png differ
diff --git a/doc/img/APTDemod_plugin_settingsdialog.png b/doc/img/APTDemod_plugin_settingsdialog.png
new file mode 100644
index 000000000..c98d10d0e
Binary files /dev/null and b/doc/img/APTDemod_plugin_settingsdialog.png differ
diff --git a/doc/img/SatelliteTracker_plugin.png b/doc/img/SatelliteTracker_plugin.png
new file mode 100644
index 000000000..77977317f
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin.png differ
diff --git a/doc/img/SatelliteTracker_plugin_control.png b/doc/img/SatelliteTracker_plugin_control.png
new file mode 100644
index 000000000..b849f1bab
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_control.png differ
diff --git a/doc/img/SatelliteTracker_plugin_map.png b/doc/img/SatelliteTracker_plugin_map.png
new file mode 100644
index 000000000..f67d0951f
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_map.png differ
diff --git a/doc/img/SatelliteTracker_plugin_passchart.png b/doc/img/SatelliteTracker_plugin_passchart.png
new file mode 100644
index 000000000..92fda83d2
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_passchart.png differ
diff --git a/doc/img/SatelliteTracker_plugin_satdata.png b/doc/img/SatelliteTracker_plugin_satdata.png
new file mode 100644
index 000000000..773c1d250
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_satdata.png differ
diff --git a/doc/img/SatelliteTracker_plugin_selection.png b/doc/img/SatelliteTracker_plugin_selection.png
new file mode 100644
index 000000000..94e56647d
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_selection.png differ
diff --git a/doc/img/SatelliteTracker_plugin_settings.png b/doc/img/SatelliteTracker_plugin_settings.png
new file mode 100644
index 000000000..57ae02f9c
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_settings.png differ
diff --git a/doc/img/SatelliteTracker_plugin_settingsdialog1.png b/doc/img/SatelliteTracker_plugin_settingsdialog1.png
new file mode 100644
index 000000000..160b1e6f6
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_settingsdialog1.png differ
diff --git a/doc/img/SatelliteTracker_plugin_settingsdialog2.png b/doc/img/SatelliteTracker_plugin_settingsdialog2.png
new file mode 100644
index 000000000..208d87b51
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_settingsdialog2.png differ
diff --git a/doc/img/SatelliteTracker_plugin_settingsdialog3.png b/doc/img/SatelliteTracker_plugin_settingsdialog3.png
new file mode 100644
index 000000000..90cb8ba0f
Binary files /dev/null and b/doc/img/SatelliteTracker_plugin_settingsdialog3.png differ
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index 716ffd55b..fbe613f39 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -359,6 +359,57 @@ if ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND LIBMBE_FOUND)
endif ()
endif ((NOT LIBDSDCC_FOUND OR LIBDSDCC_EXTERNAL) AND LIBMBE_FOUND)
+# For APT demodulator
+set(APT_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/apt.lib" CACHE INTERNAL "")
+ExternalProject_Add(apt
+ GIT_REPOSITORY https://github.com/srcejon/aptdec.git
+ GIT_TAG libaptdec
+ PREFIX "${EXTERNAL_BUILD_LIBRARIES}/apt"
+ CMAKE_ARGS ${COMMON_CMAKE_ARGS}
+ BUILD_BYPRODUCTS "${APT_LIBRARIES}"
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+ExternalProject_Get_Property(apt source_dir binary_dir)
+set(APT_FOUND ON CACHE INTERNAL "")
+set(APT_EXTERNAL ON CACHE INTERNAL "")
+set(APT_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/apt/src/apt/src" CACHE INTERNAL "")
+if (WIN32)
+ install(FILES "${SDRANGEL_BINARY_BIN_DIR}/apt${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}")
+elseif (APPLE)
+ set(APT_LIBRARIES "${binary_dir}/libapt${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "")
+ install(DIRECTORY "${binary_dir}/" DESTINATION "${INSTALL_LIB_DIR}"
+ FILES_MATCHING PATTERN "libapt*${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ set(MACOS_EXTERNAL_LIBS_FIXUP "${MACOS_EXTERNAL_LIBS_FIXUP};${binary_dir}/")
+endif ()
+
+# For Satellite Tracker feature
+# No tags for this in github - but doesn't change often
+# Fails to build with CMAKE_INTERPROCEDURAL_OPTIMIZATION=ON on Windows
+set(SGP4_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/sgp4s.lib" CACHE INTERNAL "")
+ExternalProject_Add(sgp4
+ GIT_REPOSITORY https://github.com/dnwrnr/sgp4.git
+ PREFIX "${EXTERNAL_BUILD_LIBRARIES}/sgp4"
+ CMAKE_ARGS ${COMMON_CMAKE_ARGS}
+ -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF
+ BUILD_BYPRODUCTS "${SGP4_LIBRARIES}"
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+ExternalProject_Get_Property(sgp4 source_dir binary_dir)
+set(SGP4_FOUND ON CACHE INTERNAL "")
+set(SGP4_EXTERNAL ON CACHE INTERNAL "")
+set(SGP4_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/sgp4/src/sgp4/libsgp4" CACHE INTERNAL "")
+if (WIN32)
+ install(FILES "${SDRANGEL_BINARY_BIN_DIR}/sgp4s${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}")
+elseif (APPLE)
+ set(SGP4_LIBRARIES "${binary_dir}/libsgp4s${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "")
+ install(DIRECTORY "${binary_dir}/" DESTINATION "${INSTALL_LIB_DIR}"
+ FILES_MATCHING PATTERN "libsgp4s*${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ set(MACOS_EXTERNAL_LIBS_FIXUP "${MACOS_EXTERNAL_LIBS_FIXUP};${binary_dir}/")
+endif ()
+
+
# requirements needed by many packages on windows
if (WIN32)
ExternalProject_Add(pthreads4w
diff --git a/plugins/channelrx/CMakeLists.txt b/plugins/channelrx/CMakeLists.txt
index fc20e0df6..90a06fa44 100644
--- a/plugins/channelrx/CMakeLists.txt
+++ b/plugins/channelrx/CMakeLists.txt
@@ -18,6 +18,10 @@ add_subdirectory(demodchirpchat)
add_subdirectory(demodvorsc)
add_subdirectory(demodpacket)
+if(APT_FOUND)
+ add_subdirectory(demodapt)
+endif()
+
if(LIBDSDCC_FOUND AND LIBMBE_FOUND)
add_subdirectory(demoddsd)
endif(LIBDSDCC_FOUND AND LIBMBE_FOUND)
diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp
index 21df7c8b1..94b3d1cb9 100644
--- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp
+++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp
@@ -471,6 +471,7 @@ void ADSBDemodGUI::updatePosition(Aircraft *aircraft)
swgMapItem->setAltitude(Units::feetToMetres(aircraft->m_altitude));
swgMapItem->setImage(new QString(QString("qrc:///map/%1").arg(aircraft->getImage())));
swgMapItem->setImageRotation(aircraft->m_heading);
+ swgMapItem->setImageMinZoom(11);
swgMapItem->setText(new QString(aircraft->getText(true)));
MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_adsbDemod, swgMapItem);
diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp
index 2f608063d..c8c24a0fa 100644
--- a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp
+++ b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp
@@ -41,7 +41,7 @@ void ADSBDemodSettings::resetToDefaults()
m_feedHost = "feed.adsbexchange.com";
m_feedPort = 30005;
m_feedFormat = BeastBinary;
- m_rgbColor = QColor(255, 0, 0).rgb();
+ m_rgbColor = QColor(244, 151, 57).rgb();
m_title = "ADS-B Demodulator";
m_streamIndex = 0;
m_useReverseAPI = false;
@@ -157,7 +157,7 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data)
m_feedPort = 30005;
}
- d.readU32(9, &m_rgbColor, QColor(255, 0, 0).rgb());
+ d.readU32(9, &m_rgbColor, QColor(244, 151, 57).rgb());
d.readString(11, &m_title, "ADS-B Demodulator");
d.readBool(12, &m_useReverseAPI, false);
d.readString(13, &m_reverseAPIAddress, "127.0.0.1");
diff --git a/plugins/channelrx/demodadsb/airlinelogos.qrc b/plugins/channelrx/demodadsb/airlinelogos.qrc
index 9d81292d3..8a00f5e60 100644
--- a/plugins/channelrx/demodadsb/airlinelogos.qrc
+++ b/plugins/channelrx/demodadsb/airlinelogos.qrc
@@ -4,10 +4,13 @@
airlinelogos/AAF.bmpairlinelogos/AAH.bmpairlinelogos/AAL.bmp
+ airlinelogos/AAQ.bmpairlinelogos/AAR.bmp
+ airlinelogos/AAV.bmpairlinelogos/AAW.bmpairlinelogos/AAY.bmpairlinelogos/AAZ.bmp
+ airlinelogos/AB.bmpairlinelogos/ABB.bmpairlinelogos/ABD.bmpairlinelogos/ABG.bmp
@@ -24,8 +27,11 @@
airlinelogos/ACA.bmpairlinelogos/ACG.bmpairlinelogos/ACI.bmp
+ airlinelogos/ACL.bmpairlinelogos/ACV.bmpairlinelogos/ADN.bmp
+ airlinelogos/ADO.bmp
+ airlinelogos/ADR.bmpairlinelogos/ADY.bmpairlinelogos/AEA.bmpairlinelogos/AEE.bmp
@@ -48,7 +54,13 @@
airlinelogos/AIC.bmpairlinelogos/AIE.bmpairlinelogos/AIH.bmp
+ airlinelogos/AIJ.bmp
+ airlinelogos/AIQ.bmp
+ airlinelogos/AIRBOREALIS.bmpairlinelogos/AIRCOSTA.bmp
+ airlinelogos/AIRFLAMENCO.bmp
+ airlinelogos/AIRJUAN.bmp
+ airlinelogos/AIRSEVEN.bmpairlinelogos/AIZ.bmpairlinelogos/AJA.bmpairlinelogos/AJB.bmp
@@ -57,11 +69,18 @@
airlinelogos/AJK.bmpairlinelogos/AJT.bmpairlinelogos/AKC.bmp
+ airlinelogos/AKL.bmp
+ airlinelogos/AKS.bmp
+ airlinelogos/ALK.bmp
+ airlinelogos/ALN.bmpairlinelogos/ALV.bmpairlinelogos/ALW.bmpairlinelogos/ALX.bmpairlinelogos/ALY.bmp
+ airlinelogos/AMA.bmpairlinelogos/AMC.bmp
+ airlinelogos/AMF.bmp
+ airlinelogos/AMJ.bmpairlinelogos/AMU.bmpairlinelogos/AMV.bmpairlinelogos/AMX.bmp
@@ -78,6 +97,8 @@
airlinelogos/ANT.bmpairlinelogos/ANZ.bmpairlinelogos/AOJ.bmp
+ airlinelogos/AOL.bmp
+ airlinelogos/APC.bmpairlinelogos/APF.bmpairlinelogos/APG.bmpairlinelogos/APJ.bmp
@@ -89,12 +110,14 @@
airlinelogos/ARK.bmpairlinelogos/ARN.bmpairlinelogos/ARR.bmp
+ airlinelogos/ART.bmpairlinelogos/ARU.bmpairlinelogos/ARZ.bmpairlinelogos/ASA.bmpairlinelogos/ASB.bmpairlinelogos/ASH.bmpairlinelogos/ASL.bmp
+ airlinelogos/ASP.bmpairlinelogos/ASQ.bmpairlinelogos/ASV.bmpairlinelogos/ASY.bmp
@@ -112,223 +135,579 @@
airlinelogos/AUS5.bmpairlinelogos/AUT.bmpairlinelogos/AVA.bmp
+ airlinelogos/AVIAIR.bmpairlinelogos/AVJ.bmpairlinelogos/AVN.bmpairlinelogos/AVV.bmpairlinelogos/AVW.bmp
+ airlinelogos/AWC.bmpairlinelogos/AWE.bmpairlinelogos/AWG.bmp
+ airlinelogos/AWH.bmpairlinelogos/AWI.bmpairlinelogos/AWK.bmpairlinelogos/AWM.bmpairlinelogos/AWT.bmp
+ airlinelogos/AXA.bmpairlinelogos/AXB.bmpairlinelogos/AXE.bmp
+ airlinelogos/AXG.bmpairlinelogos/AXK.bmp
+ airlinelogos/AXL.bmpairlinelogos/AXM.bmpairlinelogos/AXU.bmpairlinelogos/AYG.bmpairlinelogos/AYT.bmpairlinelogos/AZA.bmp
+ airlinelogos/AZD.bmpairlinelogos/AZG.bmpairlinelogos/AZI.bmpairlinelogos/AZM.bmpairlinelogos/AZN.bmpairlinelogos/AZO.bmp
+ airlinelogos/AZP.bmpairlinelogos/AZQ.bmpairlinelogos/AZU.bmp
+ airlinelogos/AZUf.bmpairlinelogos/AZV.bmpairlinelogos/AZW.bmp
+ airlinelogos/BAH.bmp
+ airlinelogos/BAV.bmpairlinelogos/BAW.bmp
+ airlinelogos/BAY.bmpairlinelogos/BBC.bmpairlinelogos/BBD.bmpairlinelogos/BBG.bmpairlinelogos/BCI.bmpairlinelogos/BCY.bmpairlinelogos/BDA.bmp
+ airlinelogos/BDF.bmpairlinelogos/BEE.bmpairlinelogos/BEL.bmpairlinelogos/BER.bmp
+ airlinelogos/BEY.bmp
+ airlinelogos/BEZ.bmp
+ airlinelogos/BFD.bmp
+ airlinelogos/BFL.bmpairlinelogos/BGA.bmpairlinelogos/BGH.bmpairlinelogos/BGL.bmp
+ airlinelogos/BGN.bmpairlinelogos/BGY.bmpairlinelogos/BHA.bmp
+ airlinelogos/BHL.bmpairlinelogos/BHP.bmpairlinelogos/BIE.bmp
+ airlinelogos/BJN.bmp
+ airlinelogos/BJO.bmp
+ airlinelogos/BKA.bmp
+ airlinelogos/BKP.bmpairlinelogos/BLF.bmp
+ airlinelogos/BLK.bmpairlinelogos/BLX.bmp
+ airlinelogos/BMA.bmp
+ airlinelogos/BML.bmpairlinelogos/BMR.bmp
+ airlinelogos/BNA.bmp
+ airlinelogos/BNL.bmpairlinelogos/BOE.bmpairlinelogos/BON.bmpairlinelogos/BOS.bmpairlinelogos/BOT.bmpairlinelogos/BOV.bmpairlinelogos/BOX.bmp
+ airlinelogos/BPA.bmpairlinelogos/BQB.bmp
+ airlinelogos/BRAVO.bmp
+ airlinelogos/BRH.bmpairlinelogos/BRINDABELLA.bmpairlinelogos/BRJ.bmp
+ airlinelogos/BRO.bmpairlinelogos/BRQ.bmpairlinelogos/BRU.bmpairlinelogos/BRXb.bmpairlinelogos/BSK.bmpairlinelogos/BTI.bmp
+ airlinelogos/BTK.bmpairlinelogos/BTN.bmpairlinelogos/BTQ.bmp
+ airlinelogos/BTV.bmp
+ airlinelogos/BTX.bmpairlinelogos/BUC.bmpairlinelogos/BUR.bmp
+ airlinelogos/BVI.bmpairlinelogos/BVR.bmp
+ airlinelogos/BWA.bmp
+ airlinelogos/BWJ.bmpairlinelogos/BXA.bmp
+ airlinelogos/BYA.bmp
+ airlinelogos/BYC.bmpairlinelogos/BYR.bmp
+ airlinelogos/BYS.bmp
+ airlinelogos/BZE.bmpairlinelogos/BZH.bmp
+ airlinelogos/CAA.bmpairlinelogos/CAD.bmpairlinelogos/CAI.bmp
+ airlinelogos/CAJ.bmp
+ airlinelogos/CAK.bmp
+ airlinelogos/CAL.bmpairlinelogos/CAO.bmp
+ airlinelogos/CAT.bmpairlinelogos/CAV.bmp
+ airlinelogos/CAW.bmpairlinelogos/CAY.bmp
+ airlinelogos/CAZ.bmp
+ airlinelogos/CBA.bmp
+ airlinelogos/CBG.bmp
+ airlinelogos/CBH.bmp
+ airlinelogos/CBI.bmpairlinelogos/CBJ.bmp
+ airlinelogos/CBM.bmp
+ airlinelogos/CBN.bmp
+ airlinelogos/CBX.bmpairlinelogos/CCA.bmp
+ airlinelogos/CCC.bmpairlinelogos/CCD.bmpairlinelogos/CCE.bmpairlinelogos/CCM.bmp
+ airlinelogos/CCS.bmpairlinelogos/CDA.bmpairlinelogos/CDC.bmpairlinelogos/CDG.bmp
+ airlinelogos/CDN.bmp
+ airlinelogos/CDO.bmp
+ airlinelogos/CDQ.bmp
+ airlinelogos/CDR.bmp
+ airlinelogos/CDX.bmp
+ airlinelogos/CDY.bmpairlinelogos/CEB.bmp
+ airlinelogos/CEG.bmpairlinelogos/CEL.bmpairlinelogos/CES.bmpairlinelogos/CEY.bmp
+ airlinelogos/CEZ.bmpairlinelogos/CFE.bmp
+ airlinelogos/CFF.bmpairlinelogos/CFG.bmp
+ airlinelogos/CFH.bmp
+ airlinelogos/CFL.bmp
+ airlinelogos/CFR.bmp
+ airlinelogos/CFS.bmp
+ airlinelogos/CFV.bmp
+ airlinelogos/CGE.bmpairlinelogos/CGF.bmpairlinelogos/CGH.bmpairlinelogos/CGN.bmp
+ airlinelogos/CGR.bmp
+ airlinelogos/CGZ.bmpairlinelogos/CHB.bmpairlinelogos/CHH.bmp
+ airlinelogos/CHI.bmp
+ airlinelogos/CHJ.bmp
+ airlinelogos/CHQ.bmp
+ airlinelogos/CHR.bmp
+ airlinelogos/CIA.bmp
+ airlinelogos/CIG.bmp
+ airlinelogos/CIL.bmpairlinelogos/CIM.bmp
+ airlinelogos/CIN.bmp
+ airlinelogos/CIT.bmp
+ airlinelogos/CIV.bmpairlinelogos/CJA.bmpairlinelogos/CJC.bmp
+ airlinelogos/CJE.bmp
+ airlinelogos/CJL.bmp
+ airlinelogos/CJM.bmp
+ airlinelogos/CJR.bmpairlinelogos/CJT.bmp
+ airlinelogos/CJX.bmp
+ airlinelogos/CJZ.bmpairlinelogos/CKK.bmpairlinelogos/CKS.bmp
+ airlinelogos/CLB.bmp
+ airlinelogos/CLD.bmp
+ airlinelogos/CLF.bmpairlinelogos/CLG.bmp
+ airlinelogos/CLH.bmp
+ airlinelogos/CLN.bmp
+ airlinelogos/CLO.bmp
+ airlinelogos/CLOUDGLOBAL.bmp
+ airlinelogos/CLP.bmp
+ airlinelogos/CLU.bmpairlinelogos/CLX.bmp
+ airlinelogos/CLY.bmp
+ airlinelogos/CMD.bmp
+ airlinelogos/CME.bmpairlinelogos/CMM.bmp
+ airlinelogos/CMP.bmp
+ airlinelogos/CNA.bmpairlinelogos/CND.bmp
+ airlinelogos/CNF.bmpairlinelogos/CNK.bmp
+ airlinelogos/CNP.bmp
+ airlinelogos/CNW.bmp
+ airlinelogos/COB.bmp
+ airlinelogos/COL.bmpairlinelogos/CON1.bmp
+ airlinelogos/CONa.bmp
+ airlinelogos/COO.bmp
+ airlinelogos/CORPORATEAIR.bmpairlinelogos/COT.bmp
+ airlinelogos/COW.bmp
+ airlinelogos/COY.bmpairlinelogos/CPA.bmp
+ airlinelogos/CPAC.bmp
+ airlinelogos/CPD.bmp
+ airlinelogos/CPE.bmpairlinelogos/CPN.bmp
+ airlinelogos/CPP.bmp
+ airlinelogos/CPS.bmp
+ airlinelogos/CPV.bmpairlinelogos/CPZ.bmpairlinelogos/CQH.bmpairlinelogos/CQN.bmp
+ airlinelogos/CR.bmp
+ airlinelogos/CRA.bmpairlinelogos/CRC.bmp
+ airlinelogos/CRF.bmp
+ airlinelogos/CRK.bmpairlinelogos/CRL.bmpairlinelogos/CRN.bmp
+ airlinelogos/CRNa.bmpairlinelogos/CRO.bmpairlinelogos/CRQ.bmp
+ airlinelogos/CRR.bmpairlinelogos/CRUZ.bmpairlinelogos/CSA.bmp
+ airlinelogos/CSB.bmpairlinelogos/CSC.bmpairlinelogos/CSH.bmp
+ airlinelogos/CSI.bmpairlinelogos/CSN.bmp
+ airlinelogos/CSQ.bmpairlinelogos/CSS.bmp
+ airlinelogos/CST.bmp
+ airlinelogos/CSV.bmpairlinelogos/CSZ.bmp
+ airlinelogos/CTB.bmp
+ airlinelogos/CTE.bmp
+ airlinelogos/CTF.bmp
+ airlinelogos/CTK.bmpairlinelogos/CTM.bmpairlinelogos/CTN.bmp
+ airlinelogos/CTV.bmp
+ airlinelogos/CTW.bmpairlinelogos/CUA.bmpairlinelogos/CUB.bmp
+ airlinelogos/CUH.bmp
+ airlinelogos/CUK.bmp
+ airlinelogos/CUL.bmpairlinelogos/CVA.bmp
+ airlinelogos/CVD.bmp
+ airlinelogos/CVE.bmp
+ airlinelogos/CVK.bmp
+ airlinelogos/CVR.bmp
+ airlinelogos/CVU.bmp
+ airlinelogos/CVZ.bmp
+ airlinelogos/CWA.bmpairlinelogos/CWC.bmp
+ airlinelogos/CWM.bmp
+ airlinelogos/CWY.bmpairlinelogos/CXA.bmpairlinelogos/CXB.bmp
+ airlinelogos/CXE.bmp
+ airlinelogos/CXF.bmpairlinelogos/CXH.bmp
+ airlinelogos/CXI.bmp
+ airlinelogos/CXM.bmp
+ airlinelogos/CXP.bmp
+ airlinelogos/CYF.bmpairlinelogos/CYL.bmp
+ airlinelogos/CYO.bmpairlinelogos/CYP.bmp
+ airlinelogos/CYT.bmpairlinelogos/CYZ.bmp
+ airlinelogos/DAB.bmpairlinelogos/DAC.bmp
+ airlinelogos/DAE.bmp
+ airlinelogos/DAF.bmpairlinelogos/DAH.bmp
+ airlinelogos/DAILY.bmpairlinelogos/DAL.bmp
+ airlinelogos/DAN.bmpairlinelogos/DAO.bmpairlinelogos/DAP.bmp
+ airlinelogos/DAR.bmp
+ airlinelogos/DAV.bmp
+ airlinelogos/DAZ.bmp
+ airlinelogos/DBC.bmp
+ airlinelogos/DCM.bmpairlinelogos/DCS.bmp
+ airlinelogos/DCT.bmp
+ airlinelogos/DCW.bmp
+ airlinelogos/DEJ.bmpairlinelogos/DER.bmp
+ airlinelogos/DET.bmp
+ airlinelogos/DFL.bmp
+ airlinelogos/DGX.bmp
+ airlinelogos/DHC.bmp
+ airlinelogos/DHE.bmp
+ airlinelogos/DHK.bmpairlinelogos/DHL.bmp
+ airlinelogos/DHR.bmp
+ airlinelogos/DHV.bmpairlinelogos/DHX.bmp
+ airlinelogos/DIG.bmp
+ airlinelogos/DIS.bmp
+ airlinelogos/DJC.bmpairlinelogos/DJT.bmpairlinelogos/DJU.bmpairlinelogos/DKH.bmpairlinelogos/DLA.bmpairlinelogos/DLH.bmp
+ airlinelogos/DLX.bmp
+ airlinelogos/DLY.bmp
+ airlinelogos/DMD.bmp
+ airlinelogos/DMN.bmp
+ airlinelogos/DMS.bmp
+ airlinelogos/DNC.bmp
+ airlinelogos/DND.bmp
+ airlinelogos/DNE.bmp
+ airlinelogos/DNU.bmpairlinelogos/DNV.bmp
+ airlinelogos/DNY.bmpairlinelogos/DOB.bmp
+ airlinelogos/DOC.bmp
+ airlinelogos/DOJ.bmp
+ airlinelogos/DOK.bmp
+ airlinelogos/DOM.bmp
+ airlinelogos/DOS.bmp
+ airlinelogos/DOW.bmp
+ airlinelogos/DPJ.bmp
+ airlinelogos/DQA.bmpairlinelogos/DQI.bmpairlinelogos/DRK.bmp
+ airlinelogos/DRM.bmpairlinelogos/DRU.bmp
+ airlinelogos/DRZ.bmpairlinelogos/DSM.bmp
+ airlinelogos/DSV.bmpairlinelogos/DTA.bmpairlinelogos/DTH.bmp
+ airlinelogos/DTO.bmpairlinelogos/DTR.bmp
+ airlinelogos/DVR.bmp
+ airlinelogos/DWG.bmp
+ airlinelogos/DWI.bmpairlinelogos/DYA.bmp
+ airlinelogos/DYM.bmp
+ airlinelogos/DYN.bmp
+ airlinelogos/DZR.bmpairlinelogos/EAA.bmp
+ airlinelogos/EAD.bmp
+ airlinelogos/EAF.bmp
+ airlinelogos/EAK.bmpairlinelogos/EAL.bmp
+ airlinelogos/EALOLD.bmp
+ airlinelogos/EAP.bmpairlinelogos/EAQ.bmp
+ airlinelogos/EAT.bmp
+ airlinelogos/EAU.bmp
+ airlinelogos/EAW.bmp
+ airlinelogos/EAX.bmp
+ airlinelogos/EBF.bmp
+ airlinelogos/EBS.bmp
+ airlinelogos/EBV.bmp
+ airlinelogos/ECA.bmp
+ airlinelogos/ECC.bmpairlinelogos/ECO.bmp
+ airlinelogos/EDC.bmp
+ airlinelogos/EDG.bmp
+ airlinelogos/EDR.bmp
+ airlinelogos/EDV.bmp
+ airlinelogos/EDW.bmp
+ airlinelogos/EDY.bmp
+ airlinelogos/EEL.bmp
+ airlinelogos/EES.bmp
+ airlinelogos/EEU.bmp
+ airlinelogos/EFA.bmp
+ airlinelogos/EFD.bmp
+ airlinelogos/EFF.bmp
+ airlinelogos/EFG.bmp
+ airlinelogos/EFT.bmp
+ airlinelogos/EFX.bmpairlinelogos/EGF.bmp
+ airlinelogos/EGJ.bmp
+ airlinelogos/EGL.bmp
+ airlinelogos/EGS.bmp
+ airlinelogos/EGU.bmp
+ airlinelogos/EGW.bmp
+ airlinelogos/EHR.bmp
+ airlinelogos/EIN.bmp
+ airlinelogos/EINREA.bmp
+ airlinelogos/EIS.bmp
+ airlinelogos/EJA.bmp
+ airlinelogos/EJE.bmp
+ airlinelogos/EJM.bmp
+ airlinelogos/EJO.bmp
+ airlinelogos/EJT.bmp
+ airlinelogos/EJU.bmpairlinelogos/EKA.bmp
+ airlinelogos/EKY.bmp
+ airlinelogos/ELB.bmp
+ airlinelogos/ELE.bmp
+ airlinelogos/ELF.bmp
+ airlinelogos/ELH.bmp
+ airlinelogos/ELJ.bmpairlinelogos/ELL.bmp
+ airlinelogos/ELP.bmp
+ airlinelogos/ELT.bmp
+ airlinelogos/ELW.bmp
+ airlinelogos/ELY.bmpairlinelogos/EMB.bmp
+ airlinelogos/EML.bmp
+ airlinelogos/EMM.bmp
+ airlinelogos/EMT.bmp
+ airlinelogos/ENF.bmpairlinelogos/ENJ.bmp
+ airlinelogos/ENK.bmpairlinelogos/ENT.bmp
+ airlinelogos/ENW.bmp
+ airlinelogos/ENY.bmp
+ airlinelogos/EOA.bmp
+ airlinelogos/EOK.bmpairlinelogos/EPA.bmp
+ airlinelogos/EPC.bmp
+ airlinelogos/EPJ.bmp
+ airlinelogos/EPR.bmp
+ airlinelogos/ERA.bmp
+ airlinelogos/ERF.bmp
+ airlinelogos/ERK.bmp
+ airlinelogos/ERN.bmp
+ airlinelogos/ERO.bmp
+ airlinelogos/ERR.bmpairlinelogos/ERT.bmp
+ airlinelogos/ERY.bmp
+ airlinelogos/ESF.bmp
+ airlinelogos/ESJ.bmpairlinelogos/ESQ.bmp
+ airlinelogos/ESR.bmp
+ airlinelogos/EST.bmp
+ airlinelogos/ESW.bmp
+ airlinelogos/ETA.bmpairlinelogos/ETD.bmpairlinelogos/ETH.bmp
+ airlinelogos/ETI.bmp
+ airlinelogos/ETP.bmp
+ airlinelogos/ETR.bmpairlinelogos/ETS.bmp
+ airlinelogos/EUC.bmpairlinelogos/EUG.bmp
+ airlinelogos/EUL.bmp
+ airlinelogos/EUS.bmp
+ airlinelogos/EUW.bmpairlinelogos/EVA.bmp
+ airlinelogos/EVE.bmp
+ airlinelogos/EVJ.bmp
+ airlinelogos/EVK.bmp
+ airlinelogos/EVL.bmp
+ airlinelogos/EVQ.bmp
+ airlinelogos/EVX.bmp
+ airlinelogos/EVY.bmp
+ airlinelogos/EWE.bmp
+ airlinelogos/EWF.bmpairlinelogos/EWG.bmp
+ airlinelogos/EWR.bmp
+ airlinelogos/EWS.bmp
+ airlinelogos/EXA.bmp
+ airlinelogos/EXC.bmp
+ airlinelogos/EXH.bmp
+ airlinelogos/EXN.bmp
+ airlinelogos/EXP.bmpairlinelogos/EXS.bmp
+ airlinelogos/EXSa.bmp
+ airlinelogos/EXU.bmp
+ airlinelogos/EXV.bmp
+ airlinelogos/EXY.bmp
+ airlinelogos/EXZ.bmp
+ airlinelogos/EYC.bmpairlinelogos/EYT.bmpairlinelogos/EZA.bmp
+ airlinelogos/EZB.bmpairlinelogos/EZD.bmpairlinelogos/EZE.bmp
+ airlinelogos/EZS.bmpairlinelogos/EZY.bmpairlinelogos/FAB.bmp
+ airlinelogos/FAD.bmpairlinelogos/FAG.bmpairlinelogos/FAH.bmpairlinelogos/FAT.bmp
+ airlinelogos/FBA.bmp
+ airlinelogos/FBB.bmpairlinelogos/FBD.bmpairlinelogos/FBR.bmp
+ airlinelogos/FBU.bmp
+ airlinelogos/FC.bmpairlinelogos/FCM.bmp
+ airlinelogos/FDA.bmpairlinelogos/FDB.bmp
+ airlinelogos/FDJ.bmp
+ airlinelogos/FDT.bmpairlinelogos/FDX.bmp
+ airlinelogos/FDY.bmp
+ airlinelogos/FEA.bmp
+ airlinelogos/FEG.bmp
+ airlinelogos/FEI.bmp
+ airlinelogos/FFL.bmp
+ airlinelogos/FFM.bmpairlinelogos/FFT.bmpairlinelogos/FFV.bmp
+ airlinelogos/FGW.bmpairlinelogos/FHY.bmp
+ airlinelogos/FIA.bmpairlinelogos/FIN.bmpairlinelogos/FJA.bmpairlinelogos/FJI.bmp
+ airlinelogos/FJR.bmp
+ airlinelogos/FJW.bmpairlinelogos/FLE.bmp
+ airlinelogos/FLEXIFLY.bmpairlinelogos/FLI.bmp
+ airlinelogos/FLO.bmp
+ airlinelogos/FLYPELICAN.bmpairlinelogos/FNA.bmpairlinelogos/FPK.bmpairlinelogos/FPO.bmpairlinelogos/FPY.bmpairlinelogos/FRF.bmp
+ airlinelogos/FRG.bmp
+ airlinelogos/FRH.bmpairlinelogos/FSK.bmp
+ airlinelogos/FSQ.bmp
+ airlinelogos/FSY.bmp
+ airlinelogos/FTH.bmp
+ airlinelogos/FTO.bmpairlinelogos/FTZ.bmpairlinelogos/FWI.bmp
+ airlinelogos/FXP.bmp
+ airlinelogos/FXX.bmp
+ airlinelogos/FYL.bmpairlinelogos/FZA.bmpairlinelogos/FZW.bmpairlinelogos/GAA.bmpairlinelogos/GAI.bmp
+ airlinelogos/GAJ.bmp
+ airlinelogos/GAL.bmp
+ airlinelogos/GBB.bmpairlinelogos/GBK.bmpairlinelogos/GBQ.bmp
+ airlinelogos/GCL.bmpairlinelogos/GCR.bmp
+ airlinelogos/GCT.bmpairlinelogos/GDC.bmp
+ airlinelogos/GDE.bmpairlinelogos/GEA.bmpairlinelogos/GEC.bmpairlinelogos/GEO.bmp
@@ -336,15 +715,23 @@
airlinelogos/GFG.bmpairlinelogos/GGN.bmpairlinelogos/GIA.bmp
+ airlinelogos/GJE.bmp
+ airlinelogos/GJI.bmp
+ airlinelogos/GJM.bmp
+ airlinelogos/GJS.bmp
+ airlinelogos/GJT.bmpairlinelogos/GLG.bmpairlinelogos/GLJ.bmpairlinelogos/GLO.bmpairlinelogos/GLR.bmpairlinelogos/GMI.bmpairlinelogos/GMQ.bmp
+ airlinelogos/GMR.bmpairlinelogos/GOW.bmpairlinelogos/GRL.bmp
+ airlinelogos/GSW.bmpairlinelogos/GTI.bmp
+ airlinelogos/GTR.bmpairlinelogos/GTV.bmpairlinelogos/GUG.bmpairlinelogos/GUY.bmp
@@ -355,47 +742,106 @@
airlinelogos/HBH.bmpairlinelogos/HCC.bmpairlinelogos/HCV.bmp
+ airlinelogos/HGG.bmp
+ airlinelogos/HHN.bmp
+ airlinelogos/HIM.bmp
+ airlinelogos/HKC.bmp
+ airlinelogos/HKH.bmp
+ airlinelogos/HKS.bmp
+ airlinelogos/HLE.bmp
+ airlinelogos/HLF.bmp
+ airlinelogos/HLL.bmp
+ airlinelogos/HLLa.bmpairlinelogos/HLX.bmp
+ airlinelogos/HND.bmp
+ airlinelogos/HNW.bmpairlinelogos/HOP.bmp
+ airlinelogos/HRT.bmpairlinelogos/HRV.bmp
+ airlinelogos/HTS.bmp
+ airlinelogos/HTU.bmpairlinelogos/HUN.bmpairlinelogos/HVN.bmpairlinelogos/HVY.bmp
+ airlinelogos/HWA.bmpairlinelogos/HXA.bmp
+ airlinelogos/HYA.bmp
+ airlinelogos/HYP.bmp
+ airlinelogos/HYT.bmp
+ airlinelogos/HZS.bmpairlinelogos/IAD.bmp
+ airlinelogos/IAE.bmpairlinelogos/IAW.bmp
+ airlinelogos/IAX.bmpairlinelogos/IBB.bmpairlinelogos/IBE.bmpairlinelogos/IBS.bmp
+ airlinelogos/IBX.bmpairlinelogos/ICE.bmp
+ airlinelogos/ICL.bmp
+ airlinelogos/ICV.bmpairlinelogos/IFC.bmp
+ airlinelogos/IFL.bmpairlinelogos/IGA.bmpairlinelogos/IGO.bmp
+ airlinelogos/IHO.bmp
+ airlinelogos/IIA.bmpairlinelogos/IJM.bmp
- airlinelogos/Inter Island Air.bmp
+ airlinelogos/IKA.bmp
+ airlinelogos/IMX.bmp
+ airlinelogos/IOS.bmpairlinelogos/IRA.bmp
+ airlinelogos/IRB.bmpairlinelogos/IRC.bmpairlinelogos/IRK.bmpairlinelogos/IRM.bmpairlinelogos/ISK.bmp
+ airlinelogos/ISR.bmpairlinelogos/ISS.bmpairlinelogos/ISV.bmp
+ airlinelogos/IWY.bmp
+ airlinelogos/IXR.bmp
+ airlinelogos/IYA.bmpairlinelogos/IYE.bmp
+ airlinelogos/IZA.bmp
+ airlinelogos/IZG.bmpairlinelogos/JAF.bmpairlinelogos/JAI.bmp
+ airlinelogos/JAL.bmp
+ airlinelogos/JAS.bmpairlinelogos/JAT.bmpairlinelogos/JATnew.bmpairlinelogos/JAV.bmp
+ airlinelogos/JBE.bmpairlinelogos/JBU.bmpairlinelogos/JCC.bmp
+ airlinelogos/JCL.bmp
+ airlinelogos/JCM.bmp
+ airlinelogos/JEI.bmp
+ airlinelogos/JES.bmpairlinelogos/JET.bmp
+ airlinelogos/JFL.bmpairlinelogos/JG.bmp
+ airlinelogos/JIA.bmp
+ airlinelogos/JJA.bmp
+ airlinelogos/JJP.bmp
+ airlinelogos/JKR.bmp
+ airlinelogos/JLF.bmpairlinelogos/JLL.bmp
+ airlinelogos/JMA.bmp
+ airlinelogos/JME.bmp
+ airlinelogos/JML.bmpairlinelogos/JNA.bmp
+ airlinelogos/JNL.bmp
+ airlinelogos/JON.bmpairlinelogos/JOR.bmpairlinelogos/JOY.bmp
+ airlinelogos/JRC.bmp
+ airlinelogos/JRT.bmpairlinelogos/JSA.bmpairlinelogos/JST.bmp
+ airlinelogos/JSY.bmp
+ airlinelogos/JTA.bmpairlinelogos/JTF.bmpairlinelogos/JTG.bmpairlinelogos/JUS.bmp
@@ -406,16 +852,31 @@
airlinelogos/KAB.bmpairlinelogos/KAC.bmpairlinelogos/KAL.bmp
+ airlinelogos/KAP.bmp
+ airlinelogos/KAR.bmp
+ airlinelogos/KAZ.bmp
+ airlinelogos/KBZ.bmp
+ airlinelogos/KDS.bmp
+ airlinelogos/KEM.bmp
+ airlinelogos/KEN.bmpairlinelogos/KFA.bmp
+ airlinelogos/KFE.bmpairlinelogos/KGL.bmpairlinelogos/KGO.bmp
+ airlinelogos/KGS.bmpairlinelogos/KHH.bmpairlinelogos/KHV.bmp
+ airlinelogos/KII.bmpairlinelogos/KIL.bmp
+ airlinelogos/KIS.bmpairlinelogos/KKK.bmpairlinelogos/KLC.bmp
+ airlinelogos/KLJ.bmpairlinelogos/KLM.bmp
+ airlinelogos/KME.bmpairlinelogos/KMF.bmp
+ airlinelogos/KMI.bmp
+ airlinelogos/KMK.bmpairlinelogos/KN.bmpairlinelogos/KNA.bmpairlinelogos/KNE.bmp
@@ -424,24 +885,50 @@
airlinelogos/KRE.bmpairlinelogos/KRN.bmpairlinelogos/KRP.bmp
+ airlinelogos/KSZ.bmp
+ airlinelogos/KTB.bmp
+ airlinelogos/KYE.bmpairlinelogos/KZR.bmp
+ airlinelogos/KZU.bmpairlinelogos/LAA.bmp
+ airlinelogos/LAE.bmp
+ airlinelogos/LAK.bmpairlinelogos/LAL.bmp
+ airlinelogos/LAM.bmpairlinelogos/LAN.bmp
+ airlinelogos/LAO.bmp
+ airlinelogos/LAU.bmpairlinelogos/LAV.bmpairlinelogos/LBN.bmp
+ airlinelogos/LBQ.bmpairlinelogos/LBR.bmp
+ airlinelogos/LBT.bmpairlinelogos/LBY.bmpairlinelogos/LC.bmpairlinelogos/LCO.bmp
+ airlinelogos/LDC.bmp
+ airlinelogos/LDX.bmpairlinelogos/LER.bmp
+ airlinelogos/LEX.bmpairlinelogos/LFO.bmp
+ airlinelogos/LGF.bmpairlinelogos/LGL.bmp
+ airlinelogos/LGT.bmp
+ airlinelogos/LHA.bmpairlinelogos/LIA.bmp
+ airlinelogos/LIP.bmp
+ airlinelogos/LJC.bmp
+ airlinelogos/LJY.bmpairlinelogos/LKA.bmpairlinelogos/LKE.bmp
+ airlinelogos/LKF.bmp
+ airlinelogos/LKN.bmp
+ airlinelogos/LLK.bmp
+ airlinelogos/LLL.bmp
+ airlinelogos/LLM.bmpairlinelogos/LLP.bmpairlinelogos/LLR.bmp
+ airlinelogos/LMD.bmpairlinelogos/LMU.bmpairlinelogos/LNI.bmpairlinelogos/LNK.bmp
@@ -450,80 +937,163 @@
airlinelogos/LPA.bmpairlinelogos/LPV.bmpairlinelogos/LRC.bmp
+ airlinelogos/LRS.bmp
+ airlinelogos/LSO.bmp
+ airlinelogos/LTC.bmp
+ airlinelogos/LTR.bmpairlinelogos/LUR.bmpairlinelogos/LVR.bmp
+ airlinelogos/LVT.bmp
+ airlinelogos/LWA.bmp
+ airlinelogos/LXG.bmp
+ airlinelogos/LXJ.bmpairlinelogos/LYM.bmpairlinelogos/LZB.bmpairlinelogos/MAC.bmp
+ airlinelogos/MAI.bmpairlinelogos/MAL.bmpairlinelogos/MAR.bmpairlinelogos/MAS.bmpairlinelogos/MAU.bmp
+ airlinelogos/MAV.bmp
+ airlinelogos/MAX.bmp
+ airlinelogos/MAY.bmp
+ airlinelogos/MBA.bmp
+ airlinelogos/MCM.bmp
+ airlinelogos/MDA.bmpairlinelogos/MDG.bmpairlinelogos/MEA.bmp
+ airlinelogos/MFG.bmp
+ airlinelogos/MGE.bmp
+ airlinelogos/MGL.bmp
+ airlinelogos/MGP.bmpairlinelogos/MGX.bmp
+ airlinelogos/MHO.bmpairlinelogos/MHS.bmp
+ airlinelogos/MHV.bmpairlinelogos/MJF.bmpairlinelogos/MKG.bmp
+ airlinelogos/MKR.bmpairlinelogos/MLD.bmpairlinelogos/MLH.bmp
+ airlinelogos/MLN.bmpairlinelogos/MLO.bmpairlinelogos/MLT.bmpairlinelogos/MMA.bmpairlinelogos/MMD.bmp
+ airlinelogos/MML.bmp
+ airlinelogos/MMN.bmpairlinelogos/MMZ.bmpairlinelogos/MNB.bmp
+ airlinelogos/MNG.bmpairlinelogos/MNO.bmp
+ airlinelogos/MNU.bmpairlinelogos/MON.bmpairlinelogos/MPA.bmpairlinelogos/MPE.bmpairlinelogos/MPH.bmp
+ airlinelogos/MPK.bmp
+ airlinelogos/MSA.bmpairlinelogos/MSC.bmpairlinelogos/MSE.bmpairlinelogos/MSF.bmp
+ airlinelogos/MSI.bmp
+ airlinelogos/MSJ.bmpairlinelogos/MSR.bmpairlinelogos/MSX.bmp
+ airlinelogos/MTL.bmp
+ airlinelogos/MTN.bmp
+ airlinelogos/MUL.bmp
+ airlinelogos/MUT.bmp
+ airlinelogos/MWI.bmp
+ airlinelogos/MWM.bmp
+ airlinelogos/MXD.bmp
+ airlinelogos/MYA.bmpairlinelogos/MYP.bmp
+ airlinelogos/MYW.bmpairlinelogos/MZN.bmp
+ airlinelogos/NAA.bmpairlinelogos/NAC.bmpairlinelogos/NAX.bmpairlinelogos/NCB.bmp
+ airlinelogos/NCR.bmp
+ airlinelogos/NFA.bmpairlinelogos/NGB.bmpairlinelogos/NGT.bmp
+ airlinelogos/NHX.bmpairlinelogos/NIA.bmp
+ airlinelogos/NIG.bmp
+ airlinelogos/NIH.bmp
+ airlinelogos/NIN.bmp
+ airlinelogos/NIS.bmp
+ airlinelogos/NJE.bmpairlinelogos/NKS.bmp
+ airlinelogos/NKT.bmp
+ airlinelogos/NLA.bmpairlinelogos/NLU.bmpairlinelogos/NLY.bmpairlinelogos/NMA.bmpairlinelogos/NMB.bmp
+ airlinelogos/NMG.bmpairlinelogos/NOK.bmpairlinelogos/NOS.bmpairlinelogos/NPT.bmpairlinelogos/NRL.bmp
+ airlinelogos/NRS.bmpairlinelogos/NSE.bmp
+ airlinelogos/NSJ.bmp
+ airlinelogos/NSW.bmp
+ airlinelogos/NTB.bmp
+ airlinelogos/NTF.bmp
+ airlinelogos/NUM.bmpairlinelogos/NVC.bmpairlinelogos/NVD.bmpairlinelogos/NVR.bmp
+ airlinelogos/NWG.bmp
+ airlinelogos/NWL.bmpairlinelogos/NWS.bmp
+ airlinelogos/NYS.bmp
+ airlinelogos/NYT.bmp
+ airlinelogos/NYX.bmpairlinelogos/OAE.bmpairlinelogos/OAL.bmp
+ airlinelogos/OAW.bmpairlinelogos/OBS.bmpairlinelogos/OCA.bmp
+ airlinelogos/OCL.bmp
+ airlinelogos/OES.bmpairlinelogos/OHY.bmp
+ airlinelogos/OIX.bmpairlinelogos/OKA.bmp
+ airlinelogos/OKC.bmpairlinelogos/OKS.bmpairlinelogos/OLC.bmp
+ airlinelogos/OLS.bmpairlinelogos/OMA.bmp
+ airlinelogos/OMS.bmp
+ airlinelogos/OMT.bmpairlinelogos/ONE.bmpairlinelogos/ONX.bmpairlinelogos/OPJ.bmpairlinelogos/ORB.bmp
+ airlinelogos/ORN.bmpairlinelogos/OTC.bmp
+ airlinelogos/OTF.bmpairlinelogos/OVA.bmp
+ airlinelogos/OWT.bmp
+ airlinelogos/OXM.bmpairlinelogos/OZW.bmp
+ airlinelogos/PAC.bmp
+ airlinelogos/PACIFIC.bmpairlinelogos/PAG.bmp
+ airlinelogos/PAJ.bmpairlinelogos/PAL.bmpairlinelogos/PAM.bmp
+ airlinelogos/PAO.bmp
+ airlinelogos/PAPILLON.bmp
+ airlinelogos/PAV.bmp
+ airlinelogos/PBD.bmp
+ airlinelogos/PCO.bmpairlinelogos/PCP.bmpairlinelogos/PER.bmpairlinelogos/PEV.bmp
@@ -531,13 +1101,21 @@
airlinelogos/PFZ.bmpairlinelogos/PGA.bmpairlinelogos/PGT.bmp
+ airlinelogos/PHU.bmpairlinelogos/PIA.bmpairlinelogos/PIC.bmp
+ airlinelogos/PICa.bmp
+ airlinelogos/PICb.bmp
+ airlinelogos/PJC.bmp
+ airlinelogos/PJS.bmpairlinelogos/PKZ.bmp
+ airlinelogos/PLANET9.bmpairlinelogos/PLM.bmpairlinelogos/PLV.bmpairlinelogos/PLY.bmpairlinelogos/PMT.bmp
+ airlinelogos/PNC.bmp
+ airlinelogos/PNX.bmpairlinelogos/POE.bmpairlinelogos/POT.bmpairlinelogos/PRF.bmp
@@ -546,167 +1124,310 @@
airlinelogos/PSC.bmpairlinelogos/PST.bmpairlinelogos/PTB.bmp
+ airlinelogos/PTH.bmpairlinelogos/PTR.bmp
+ airlinelogos/PUA.bmp
+ airlinelogos/PUE.bmp
+ airlinelogos/PUN.bmp
+ airlinelogos/PVD.bmpairlinelogos/PVN.bmp
+ airlinelogos/PVO.bmp
+ airlinelogos/PVV.bmpairlinelogos/PWD.bmp
+ airlinelogos/PXG.bmpairlinelogos/QAJ.bmp
+ airlinelogos/QAZ.bmp
+ airlinelogos/QBA.bmpairlinelogos/QDA.bmpairlinelogos/QFA.bmpairlinelogos/QLK.bmp
+ airlinelogos/QSM.bmpairlinelogos/QTR.bmp
+ airlinelogos/QXE.bmp
+ airlinelogos/RAC.bmpairlinelogos/RAE.bmpairlinelogos/RAM.bmpairlinelogos/RAR.bmpairlinelogos/RBA.bmp
+ airlinelogos/RBB.bmpairlinelogos/RBG.bmp
+ airlinelogos/RDS.bmpairlinelogos/REU.bmpairlinelogos/RGE.bmpairlinelogos/RJA.bmpairlinelogos/RJD.bmpairlinelogos/RKM.bmp
+ airlinelogos/RKS.bmpairlinelogos/RLA.bmpairlinelogos/RLH.bmpairlinelogos/RLK.bmpairlinelogos/RLU.bmpairlinelogos/RLX.bmp
+ airlinelogos/RLY.bmp
+ airlinelogos/RMY.bmp
+ airlinelogos/RNA.bmpairlinelogos/RNV.bmpairlinelogos/ROI.bmp
+ airlinelogos/ROJ.bmpairlinelogos/ROT.bmpairlinelogos/ROU.bmp
+ airlinelogos/RPA.bmpairlinelogos/RPB.bmp
+ airlinelogos/RPM.bmp
+ airlinelogos/RSI.bmpairlinelogos/RSY.bmp
+ airlinelogos/RTL.bmpairlinelogos/RUC.bmp
+ airlinelogos/RUK.bmp
+ airlinelogos/RUN.bmp
+ airlinelogos/RVP.bmp
+ airlinelogos/RWD.bmpairlinelogos/RWG.bmpairlinelogos/RWZ.bmpairlinelogos/RXA.bmp
+ airlinelogos/RYL.bmpairlinelogos/RYR.bmpairlinelogos/RYW.bmpairlinelogos/RZO.bmp
+ airlinelogos/SAA.bmpairlinelogos/SAI.bmp
+ airlinelogos/SAR.bmpairlinelogos/SAS.bmp
+ airlinelogos/SAW.bmp
+ airlinelogos/SAY.bmp
+ airlinelogos/SBB.bmp
+ airlinelogos/SBI.bmp
+ airlinelogos/SBL.bmpairlinelogos/SBM.bmp
+ airlinelogos/SBS.bmp
+ airlinelogos/SBU.bmp
+ airlinelogos/SCN.bmpairlinelogos/SCO.bmpairlinelogos/SCX.bmp
+ airlinelogos/SDA.bmp
+ airlinelogos/SDG.bmpairlinelogos/SDM.bmp
+ airlinelogos/SDU.bmp
+ airlinelogos/SEH.bmpairlinelogos/SEJ.bmp
+ airlinelogos/SEP.bmp
+ airlinelogos/SET.bmpairlinelogos/SEY.bmpairlinelogos/SFF.bmp
+ airlinelogos/SFJ.bmp
+ airlinelogos/SFR.bmp
+ airlinelogos/SFS.bmpairlinelogos/SFW.bmpairlinelogos/SGA.bmp
+ airlinelogos/SGB.bmpairlinelogos/SGG.bmp
+ airlinelogos/SGQ.bmp
+ airlinelogos/SHH.bmp
+ airlinelogos/SHI.bmpairlinelogos/SHU.bmpairlinelogos/SIA.bmpairlinelogos/SID.bmpairlinelogos/SIF.bmp
+ airlinelogos/SIL.bmpairlinelogos/SIN.bmp
+ airlinelogos/SIS.bmp
+ airlinelogos/SIY.bmp
+ airlinelogos/SJJ.bmpairlinelogos/SJO.bmp
+ airlinelogos/SJX.bmp
+ airlinelogos/SJY.bmp
+ airlinelogos/SKIPPERS.bmpairlinelogos/SKK.bmpairlinelogos/SKP.bmpairlinelogos/SKU.bmpairlinelogos/SKV.bmp
+ airlinelogos/SKW.bmp
+ airlinelogos/SKX.bmp
+ airlinelogos/SKY.bmp
+ airlinelogos/SKYDIVESTRATH.bmp
+ airlinelogos/SKYDIVESTRATHa.bmpairlinelogos/SKZ.bmpairlinelogos/SLI.bmpairlinelogos/SLK.bmpairlinelogos/SLM.bmp
+ airlinelogos/SLQ.bmpairlinelogos/SLX.bmpairlinelogos/SME.bmpairlinelogos/SMJ.bmpairlinelogos/SMR.bmp
+ airlinelogos/SNA.bmp
+ airlinelogos/SNG.bmp
+ airlinelogos/SNJ.bmp
+ airlinelogos/SOL.bmp
+ airlinelogos/SONOCO.bmp
+ airlinelogos/SOO.bmpairlinelogos/SOR.bmpairlinelogos/SOV.bmp
+ airlinelogos/SOW.bmp
+ airlinelogos/SPD.bmpairlinelogos/SPR.bmpairlinelogos/SQC.bmp
+ airlinelogos/SQH.bmp
+ airlinelogos/SQP.bmpairlinelogos/SQS.bmp
+ airlinelogos/SRC.bmp
+ airlinelogos/SRN.bmp
+ airlinelogos/SRQ.bmpairlinelogos/SRR.bmp
+ airlinelogos/SSF.bmpairlinelogos/SSQ.bmpairlinelogos/SSV.bmp
+ airlinelogos/SSX.bmp
+ airlinelogos/STP.bmp
+ airlinelogos/STRAT.bmp
+ airlinelogos/SUD.bmpairlinelogos/SUS.bmpairlinelogos/SVA.bmpairlinelogos/SVR.bmp
+ airlinelogos/SVW.bmpairlinelogos/SWA.bmpairlinelogos/SWAnew.bmpairlinelogos/SWG.bmpairlinelogos/SWM.bmp
+ airlinelogos/SWQ.bmpairlinelogos/SWR.bmpairlinelogos/SWT.bmp
+ airlinelogos/SXN.bmpairlinelogos/SXS.bmp
+ airlinelogos/SYG.bmpairlinelogos/SYL.bmp
+ airlinelogos/SZN.bmp
+ airlinelogos/TAG.bmpairlinelogos/TAI.bmpairlinelogos/TAK.bmpairlinelogos/TAM.bmp
+ airlinelogos/TAN.bmpairlinelogos/TAO.bmpairlinelogos/TAP.bmp
+ airlinelogos/TAPexp.bmpairlinelogos/TAR.bmpairlinelogos/TAY.bmpairlinelogos/TBA.bmp
+ airlinelogos/TBM.bmpairlinelogos/TBN.bmpairlinelogos/TBZ.bmp
+ airlinelogos/TCB.bmpairlinelogos/TCV.bmpairlinelogos/TCW.bmpairlinelogos/TCX.bmpairlinelogos/TDR.bmp
+ airlinelogos/TEK.bmp
+ airlinelogos/TEU.bmp
+ airlinelogos/TFF.bmpairlinelogos/TFL.bmp
+ airlinelogos/TGG.bmp
+ airlinelogos/TGN.bmpairlinelogos/TGW.bmpairlinelogos/TGZ.bmpairlinelogos/THA.bmp
+ airlinelogos/THD.bmpairlinelogos/THE.bmpairlinelogos/THT.bmpairlinelogos/THY.bmpairlinelogos/THYANA.bmpairlinelogos/TIA.bmp
+ airlinelogos/TIS.bmp
+ airlinelogos/TIV.bmpairlinelogos/TIW.bmp
+ airlinelogos/TJB.bmp
+ airlinelogos/TJJ.bmpairlinelogos/TJK.bmpairlinelogos/TJS.bmp
+ airlinelogos/TJT.bmp
+ airlinelogos/TKK.bmp
+ airlinelogos/TLM.bmpairlinelogos/TMA.bmp
+ airlinelogos/TMG.bmpairlinelogos/TMN.bmpairlinelogos/TMW.bmpairlinelogos/TNA.bmpairlinelogos/TNO.bmp
+ airlinelogos/TNU.bmp
+ airlinelogos/TNX.bmp
+ airlinelogos/TOK.bmpairlinelogos/TOM.bmp
+ airlinelogos/TOR.bmpairlinelogos/TPA.bmpairlinelogos/TPC.bmpairlinelogos/TPU.bmpairlinelogos/TRA.bmp
+ airlinelogos/TRJ.bmpairlinelogos/TSC.bmpairlinelogos/TSG.bmpairlinelogos/TSH.bmpairlinelogos/TSO.bmpairlinelogos/TSY.bmp
+ airlinelogos/TTE.bmp
+ airlinelogos/TTI.bmpairlinelogos/TTL.bmp
+ airlinelogos/TTW.bmpairlinelogos/TUA.bmpairlinelogos/TUI.bmp
+ airlinelogos/TUP.bmpairlinelogos/TUS.bmpairlinelogos/TUY.bmpairlinelogos/TVF.bmp
+ airlinelogos/TVJ.bmpairlinelogos/TVP.bmpairlinelogos/TVQ.bmp
+ airlinelogos/TVR.bmpairlinelogos/TVS.bmp
+ airlinelogos/TVV.bmp
+ airlinelogos/TWB.bmpairlinelogos/TWI.bmp
+ airlinelogos/TWY.bmp
+ airlinelogos/TYA.bmpairlinelogos/UAE.bmpairlinelogos/UAL.bmp
+ airlinelogos/UBA.bmpairlinelogos/UBD.bmp
+ airlinelogos/UBG.bmpairlinelogos/UCA.bmp
+ airlinelogos/UDN.bmpairlinelogos/UEA.bmp
+ airlinelogos/UFC.bmp
+ airlinelogos/UGD.bmp
+ airlinelogos/UIA.bmp
+ airlinelogos/UJC.bmpairlinelogos/UJX.bmp
+ airlinelogos/UKM.bmp
+ airlinelogos/ULC.bmpairlinelogos/ULG.bmp
+ airlinelogos/UNA.bmpairlinelogos/UPS.bmpairlinelogos/URG.bmpairlinelogos/URS.bmp
+ airlinelogos/USC.bmpairlinelogos/UTA.bmpairlinelogos/UTN.bmpairlinelogos/UTP.bmpairlinelogos/UTY.bmp
+ airlinelogos/UVT.bmp
+ airlinelogos/UWJ.bmpairlinelogos/UZB.bmp
+ airlinelogos/VAA.bmp
+ airlinelogos/VAJ.bmpairlinelogos/VAL.bmpairlinelogos/VAR.bmpairlinelogos/VAS.bmpairlinelogos/VAU.bmpairlinelogos/VAV.bmp
+ airlinelogos/VBA.bmpairlinelogos/VBB.bmpairlinelogos/VBW.bmp
+ airlinelogos/VCJ.bmpairlinelogos/VCV.bmpairlinelogos/VDA.bmp
+ airlinelogos/VDR.bmp
+ airlinelogos/VEC.bmpairlinelogos/VEL.bmp
+ airlinelogos/VES.bmp
+ airlinelogos/VET.bmpairlinelogos/VFC.bmpairlinelogos/VIL.bmpairlinelogos/VIM.bmp
@@ -715,44 +1436,79 @@
airlinelogos/VIV.bmpairlinelogos/VJC.bmpairlinelogos/VJS.bmp
+ airlinelogos/VJT.bmpairlinelogos/VKG.bmp
+ airlinelogos/VKGOLD.bmpairlinelogos/VLG.bmp
+ airlinelogos/VLJ.bmpairlinelogos/VLK.bmpairlinelogos/VLM.bmpairlinelogos/VMP.bmpairlinelogos/VNE.bmpairlinelogos/VNL.bmp
+ airlinelogos/VOC.bmpairlinelogos/VOE.bmp
+ airlinelogos/VOI.bmpairlinelogos/VOZ.bmpairlinelogos/VPA.bmp
+ airlinelogos/VPC.bmp
+ airlinelogos/VPE.bmpairlinelogos/VRD.bmpairlinelogos/VRE.bmpairlinelogos/VRG.bmpairlinelogos/VSV.bmpairlinelogos/VTA.bmp
+ airlinelogos/VTE.bmpairlinelogos/VTI.bmpairlinelogos/VTM.bmp
+ airlinelogos/VTS.bmp
+ airlinelogos/VTU.bmpairlinelogos/VUN.bmpairlinelogos/VVC.bmp
+ airlinelogos/VVV.bmp
+ airlinelogos/WAA.bmpairlinelogos/WAJ.bmp
+ airlinelogos/WAL.bmp
+ airlinelogos/WAU.bmpairlinelogos/WDA.bmp
+ airlinelogos/WDE.bmpairlinelogos/WEN.bmpairlinelogos/WEW.bmpairlinelogos/WFR.bmp
+ airlinelogos/WGN.bmp
+ airlinelogos/WHS.bmp
+ airlinelogos/WIA.bmpairlinelogos/WIF.bmp
+ airlinelogos/WIL.bmpairlinelogos/WJA.bmp
+ airlinelogos/WLB.bmpairlinelogos/WLC.bmp
+ airlinelogos/WMN.bmp
+ airlinelogos/WON.bmp
+ airlinelogos/WORLD2FLY.bmpairlinelogos/WOW.bmpairlinelogos/WRC.bmpairlinelogos/WSG.bmp
+ airlinelogos/WSN.bmp
+ airlinelogos/WSW.bmpairlinelogos/WUK.bmp
+ airlinelogos/WWI.bmpairlinelogos/WWW.bmpairlinelogos/WZZ.bmpairlinelogos/XAH.bmp
+ airlinelogos/XAI.bmp
+ airlinelogos/XAU.bmpairlinelogos/XAX.bmpairlinelogos/XLF.bmp
+ airlinelogos/XLK.bmpairlinelogos/XLR.bmpairlinelogos/XME.bmp
+ airlinelogos/XOJ.bmp
+ airlinelogos/XRC.bmp
+ airlinelogos/XRO.bmp
+ airlinelogos/YEL.bmpairlinelogos/YZR.bmp
+ airlinelogos/ZOM.bmp
+
\ No newline at end of file
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/AAL.bmp
index 54efae32f..0f4d39e83 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/AAL.bmp and b/plugins/channelrx/demodadsb/airlinelogos/AAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AAQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/AAQ.bmp
new file mode 100644
index 000000000..a114e7dd4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AAQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AAV.bmp b/plugins/channelrx/demodadsb/airlinelogos/AAV.bmp
new file mode 100644
index 000000000..d3cfdf7a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AAV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AB.bmp b/plugins/channelrx/demodadsb/airlinelogos/AB.bmp
new file mode 100644
index 000000000..5edb20309
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ABB.bmp b/plugins/channelrx/demodadsb/airlinelogos/ABB.bmp
index 0750048d1..bbb4fa376 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/ABB.bmp and b/plugins/channelrx/demodadsb/airlinelogos/ABB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ABS.bmp b/plugins/channelrx/demodadsb/airlinelogos/ABS.bmp
index 4e774f879..92075099c 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/ABS.bmp and b/plugins/channelrx/demodadsb/airlinelogos/ABS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ABY.bmp b/plugins/channelrx/demodadsb/airlinelogos/ABY.bmp
index 8d0f7c894..3dc49c5b1 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/ABY.bmp and b/plugins/channelrx/demodadsb/airlinelogos/ABY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ACL.bmp b/plugins/channelrx/demodadsb/airlinelogos/ACL.bmp
new file mode 100644
index 000000000..db4ce4b57
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ACL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ADO.bmp b/plugins/channelrx/demodadsb/airlinelogos/ADO.bmp
new file mode 100644
index 000000000..151ef8a08
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ADO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ADR.bmp b/plugins/channelrx/demodadsb/airlinelogos/ADR.bmp
new file mode 100644
index 000000000..fbbf358b1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ADR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AFL.bmp b/plugins/channelrx/demodadsb/airlinelogos/AFL.bmp
index d0ff2cdfa..a1d667321 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/AFL.bmp and b/plugins/channelrx/demodadsb/airlinelogos/AFL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AHO.bmp b/plugins/channelrx/demodadsb/airlinelogos/AHO.bmp
index e75830a87..00cf805c4 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/AHO.bmp and b/plugins/channelrx/demodadsb/airlinelogos/AHO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AHY.bmp b/plugins/channelrx/demodadsb/airlinelogos/AHY.bmp
index c88ba8eb8..600fefe18 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/AHY.bmp and b/plugins/channelrx/demodadsb/airlinelogos/AHY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AIJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/AIJ.bmp
new file mode 100644
index 000000000..76e83a353
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AIJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AIQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/AIQ.bmp
new file mode 100644
index 000000000..277c280c0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AIQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AIRBOREALIS.bmp b/plugins/channelrx/demodadsb/airlinelogos/AIRBOREALIS.bmp
new file mode 100644
index 000000000..579987dce
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AIRBOREALIS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AIRFLAMENCO.bmp b/plugins/channelrx/demodadsb/airlinelogos/AIRFLAMENCO.bmp
new file mode 100644
index 000000000..7513d1874
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AIRFLAMENCO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AIRJUAN.bmp b/plugins/channelrx/demodadsb/airlinelogos/AIRJUAN.bmp
new file mode 100644
index 000000000..155ca3172
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AIRJUAN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AIRSEVEN.bmp b/plugins/channelrx/demodadsb/airlinelogos/AIRSEVEN.bmp
new file mode 100644
index 000000000..ab7bcd548
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AIRSEVEN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AKL.bmp b/plugins/channelrx/demodadsb/airlinelogos/AKL.bmp
new file mode 100644
index 000000000..db4382cfd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AKL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AKS.bmp b/plugins/channelrx/demodadsb/airlinelogos/AKS.bmp
new file mode 100644
index 000000000..e547c467d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AKS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ALK.bmp b/plugins/channelrx/demodadsb/airlinelogos/ALK.bmp
new file mode 100644
index 000000000..0d8381efc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ALK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ALN.bmp b/plugins/channelrx/demodadsb/airlinelogos/ALN.bmp
new file mode 100644
index 000000000..4f801926f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ALN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AMA.bmp b/plugins/channelrx/demodadsb/airlinelogos/AMA.bmp
new file mode 100644
index 000000000..41852938d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AMA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AMF.bmp b/plugins/channelrx/demodadsb/airlinelogos/AMF.bmp
new file mode 100644
index 000000000..b93d56868
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AMF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AMJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/AMJ.bmp
new file mode 100644
index 000000000..ae5788fd2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AMJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AOL.bmp b/plugins/channelrx/demodadsb/airlinelogos/AOL.bmp
new file mode 100644
index 000000000..298bee3e3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AOL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/APC.bmp b/plugins/channelrx/demodadsb/airlinelogos/APC.bmp
new file mode 100644
index 000000000..94d5434cf
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/APC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/APK.bmp b/plugins/channelrx/demodadsb/airlinelogos/APK.bmp
index 4551ccfdb..9781c4161 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/APK.bmp and b/plugins/channelrx/demodadsb/airlinelogos/APK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ARA.bmp b/plugins/channelrx/demodadsb/airlinelogos/ARA.bmp
index eb585d2a1..f228036c3 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/ARA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/ARA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ART.bmp b/plugins/channelrx/demodadsb/airlinelogos/ART.bmp
new file mode 100644
index 000000000..f603b933a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ART.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ASP.bmp b/plugins/channelrx/demodadsb/airlinelogos/ASP.bmp
new file mode 100644
index 000000000..30fa3ee2a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ASP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ASV.bmp b/plugins/channelrx/demodadsb/airlinelogos/ASV.bmp
index 61915eb5b..a469f8ae9 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/ASV.bmp and b/plugins/channelrx/demodadsb/airlinelogos/ASV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AUL.bmp b/plugins/channelrx/demodadsb/airlinelogos/AUL.bmp
index 606fa25eb..509d185f3 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/AUL.bmp and b/plugins/channelrx/demodadsb/airlinelogos/AUL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AVIAIR.bmp b/plugins/channelrx/demodadsb/airlinelogos/AVIAIR.bmp
new file mode 100644
index 000000000..64d8cb558
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AVIAIR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AWC.bmp b/plugins/channelrx/demodadsb/airlinelogos/AWC.bmp
new file mode 100644
index 000000000..faa6e9f5f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AWC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AWH.bmp b/plugins/channelrx/demodadsb/airlinelogos/AWH.bmp
new file mode 100644
index 000000000..c22bd50b3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AWH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AXA.bmp b/plugins/channelrx/demodadsb/airlinelogos/AXA.bmp
new file mode 100644
index 000000000..a183f778d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AXA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AXG.bmp b/plugins/channelrx/demodadsb/airlinelogos/AXG.bmp
new file mode 100644
index 000000000..9d6491472
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AXG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AXL.bmp b/plugins/channelrx/demodadsb/airlinelogos/AXL.bmp
new file mode 100644
index 000000000..275d4dcb4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AXL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AZD.bmp b/plugins/channelrx/demodadsb/airlinelogos/AZD.bmp
new file mode 100644
index 000000000..7a9849a76
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AZD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AZO.bmp b/plugins/channelrx/demodadsb/airlinelogos/AZO.bmp
index 12a29722b..03e044bd5 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/AZO.bmp and b/plugins/channelrx/demodadsb/airlinelogos/AZO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AZP.bmp b/plugins/channelrx/demodadsb/airlinelogos/AZP.bmp
new file mode 100644
index 000000000..4b9c226f4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AZP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/AZUf.bmp b/plugins/channelrx/demodadsb/airlinelogos/AZUf.bmp
new file mode 100644
index 000000000..3dd7e9307
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/AZUf.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BAH.bmp b/plugins/channelrx/demodadsb/airlinelogos/BAH.bmp
new file mode 100644
index 000000000..0a4c4be77
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BAH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BAV.bmp b/plugins/channelrx/demodadsb/airlinelogos/BAV.bmp
new file mode 100644
index 000000000..1dca5acec
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BAV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BAY.bmp b/plugins/channelrx/demodadsb/airlinelogos/BAY.bmp
new file mode 100644
index 000000000..6808d7a0b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BAY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BBD.bmp b/plugins/channelrx/demodadsb/airlinelogos/BBD.bmp
index d7c7301d5..a881252c6 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/BBD.bmp and b/plugins/channelrx/demodadsb/airlinelogos/BBD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BCI.bmp b/plugins/channelrx/demodadsb/airlinelogos/BCI.bmp
index f05887335..a85f21f5a 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/BCI.bmp and b/plugins/channelrx/demodadsb/airlinelogos/BCI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BDA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BDA.bmp
index aa6988f02..46a310b94 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/BDA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/BDA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BDF.bmp b/plugins/channelrx/demodadsb/airlinelogos/BDF.bmp
new file mode 100644
index 000000000..535d30e71
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BDF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BEL.bmp b/plugins/channelrx/demodadsb/airlinelogos/BEL.bmp
index 2527ca8f6..7ae8d4ed5 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/BEL.bmp and b/plugins/channelrx/demodadsb/airlinelogos/BEL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BEY.bmp b/plugins/channelrx/demodadsb/airlinelogos/BEY.bmp
new file mode 100644
index 000000000..f90d47a8b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BEY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BEZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/BEZ.bmp
new file mode 100644
index 000000000..92bf2b5df
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BEZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BFD.bmp b/plugins/channelrx/demodadsb/airlinelogos/BFD.bmp
new file mode 100644
index 000000000..cacfd90b8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BFD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BFL.bmp b/plugins/channelrx/demodadsb/airlinelogos/BFL.bmp
new file mode 100644
index 000000000..fbfdef9d8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BFL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BGN.bmp b/plugins/channelrx/demodadsb/airlinelogos/BGN.bmp
new file mode 100644
index 000000000..b4c576d2e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BGN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BHL.bmp b/plugins/channelrx/demodadsb/airlinelogos/BHL.bmp
new file mode 100644
index 000000000..80730b99c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BHL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BJN.bmp b/plugins/channelrx/demodadsb/airlinelogos/BJN.bmp
new file mode 100644
index 000000000..88814f7b8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BJN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BJO.bmp b/plugins/channelrx/demodadsb/airlinelogos/BJO.bmp
new file mode 100644
index 000000000..39945c7e4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BJO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BKA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BKA.bmp
new file mode 100644
index 000000000..df9e4ea2d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BKA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BKP.bmp b/plugins/channelrx/demodadsb/airlinelogos/BKP.bmp
new file mode 100644
index 000000000..b1286c73a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BKP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BLK.bmp b/plugins/channelrx/demodadsb/airlinelogos/BLK.bmp
new file mode 100644
index 000000000..42444aa73
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BLK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BMA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BMA.bmp
new file mode 100644
index 000000000..dc339e894
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BMA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BML.bmp b/plugins/channelrx/demodadsb/airlinelogos/BML.bmp
new file mode 100644
index 000000000..f69a5c9ae
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BML.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BNA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BNA.bmp
new file mode 100644
index 000000000..73667b3e7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BNA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BNL.bmp b/plugins/channelrx/demodadsb/airlinelogos/BNL.bmp
new file mode 100644
index 000000000..ccf77b5db
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BNL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BPA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BPA.bmp
new file mode 100644
index 000000000..4b1709ba0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BPA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BQB.bmp b/plugins/channelrx/demodadsb/airlinelogos/BQB.bmp
index 004e761db..23b134182 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/BQB.bmp and b/plugins/channelrx/demodadsb/airlinelogos/BQB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BRAVO.bmp b/plugins/channelrx/demodadsb/airlinelogos/BRAVO.bmp
new file mode 100644
index 000000000..0d79ce452
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BRAVO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BRH.bmp b/plugins/channelrx/demodadsb/airlinelogos/BRH.bmp
new file mode 100644
index 000000000..38c9ecdfc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BRH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BRO.bmp b/plugins/channelrx/demodadsb/airlinelogos/BRO.bmp
new file mode 100644
index 000000000..2f23713a8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BRO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BRU.bmp b/plugins/channelrx/demodadsb/airlinelogos/BRU.bmp
index 22936762f..b7ea31399 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/BRU.bmp and b/plugins/channelrx/demodadsb/airlinelogos/BRU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BTK.bmp b/plugins/channelrx/demodadsb/airlinelogos/BTK.bmp
new file mode 100644
index 000000000..a2b54cc81
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BTK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BTV.bmp b/plugins/channelrx/demodadsb/airlinelogos/BTV.bmp
new file mode 100644
index 000000000..50dc88a00
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BTV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BTX.bmp b/plugins/channelrx/demodadsb/airlinelogos/BTX.bmp
new file mode 100644
index 000000000..ce4da47bd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BTX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BVI.bmp b/plugins/channelrx/demodadsb/airlinelogos/BVI.bmp
new file mode 100644
index 000000000..1a4d2eceb
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BVI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BWA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BWA.bmp
new file mode 100644
index 000000000..b57c51f2f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BWA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BWJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/BWJ.bmp
new file mode 100644
index 000000000..0567bf995
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BWJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BYA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BYA.bmp
new file mode 100644
index 000000000..dc904968c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BYA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BYC.bmp b/plugins/channelrx/demodadsb/airlinelogos/BYC.bmp
new file mode 100644
index 000000000..00d419584
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BYC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BYS.bmp b/plugins/channelrx/demodadsb/airlinelogos/BYS.bmp
new file mode 100644
index 000000000..adc6254a6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BYS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/BZE.bmp b/plugins/channelrx/demodadsb/airlinelogos/BZE.bmp
new file mode 100644
index 000000000..ecf9987ab
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/BZE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAA.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAA.bmp
new file mode 100644
index 000000000..157330ddd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CAA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAI.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAI.bmp
index 810b215ed..53d7f26af 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CAI.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CAI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAJ.bmp
new file mode 100644
index 000000000..44377bac0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CAJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAK.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAK.bmp
new file mode 100644
index 000000000..dbc901fd3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CAK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAL.bmp
new file mode 100644
index 000000000..06b594840
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAT.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAT.bmp
new file mode 100644
index 000000000..52a5b2f28
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CAT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAW.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAW.bmp
new file mode 100644
index 000000000..6dd73fa83
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CAW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CAZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CAZ.bmp
new file mode 100644
index 000000000..0fb37a823
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CAZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CBA.bmp b/plugins/channelrx/demodadsb/airlinelogos/CBA.bmp
new file mode 100644
index 000000000..8cbc390c7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CBA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CBG.bmp b/plugins/channelrx/demodadsb/airlinelogos/CBG.bmp
new file mode 100644
index 000000000..96dd47d54
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CBG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CBH.bmp b/plugins/channelrx/demodadsb/airlinelogos/CBH.bmp
new file mode 100644
index 000000000..42960b097
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CBH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CBI.bmp b/plugins/channelrx/demodadsb/airlinelogos/CBI.bmp
new file mode 100644
index 000000000..f19060b05
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CBI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CBM.bmp b/plugins/channelrx/demodadsb/airlinelogos/CBM.bmp
new file mode 100644
index 000000000..72229b714
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CBM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CBN.bmp b/plugins/channelrx/demodadsb/airlinelogos/CBN.bmp
new file mode 100644
index 000000000..d021a3020
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CBN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CBX.bmp b/plugins/channelrx/demodadsb/airlinelogos/CBX.bmp
new file mode 100644
index 000000000..d4703c8ac
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CBX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CCC.bmp b/plugins/channelrx/demodadsb/airlinelogos/CCC.bmp
new file mode 100644
index 000000000..41648777f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CCC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CCS.bmp b/plugins/channelrx/demodadsb/airlinelogos/CCS.bmp
new file mode 100644
index 000000000..78d506757
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CCS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CDN.bmp b/plugins/channelrx/demodadsb/airlinelogos/CDN.bmp
new file mode 100644
index 000000000..1328d964d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CDN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CDO.bmp b/plugins/channelrx/demodadsb/airlinelogos/CDO.bmp
new file mode 100644
index 000000000..f2e5e43d9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CDO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CDQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CDQ.bmp
new file mode 100644
index 000000000..74171c899
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CDQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CDR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CDR.bmp
new file mode 100644
index 000000000..968c77ddd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CDR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CDX.bmp b/plugins/channelrx/demodadsb/airlinelogos/CDX.bmp
new file mode 100644
index 000000000..d6b01d695
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CDX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CDY.bmp b/plugins/channelrx/demodadsb/airlinelogos/CDY.bmp
new file mode 100644
index 000000000..ff48f9c6c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CDY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CEB.bmp b/plugins/channelrx/demodadsb/airlinelogos/CEB.bmp
index 430bbd4ef..e4c8d20b2 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CEB.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CEB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CEG.bmp b/plugins/channelrx/demodadsb/airlinelogos/CEG.bmp
new file mode 100644
index 000000000..dd0bcb954
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CEG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CEZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CEZ.bmp
new file mode 100644
index 000000000..ae6babcc6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CEZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CFF.bmp b/plugins/channelrx/demodadsb/airlinelogos/CFF.bmp
new file mode 100644
index 000000000..f2cf96953
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CFF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CFG.bmp b/plugins/channelrx/demodadsb/airlinelogos/CFG.bmp
index 55bef69c5..68f50a55e 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CFG.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CFG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CFH.bmp b/plugins/channelrx/demodadsb/airlinelogos/CFH.bmp
new file mode 100644
index 000000000..23b415406
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CFH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CFL.bmp b/plugins/channelrx/demodadsb/airlinelogos/CFL.bmp
new file mode 100644
index 000000000..d6eb4bbac
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CFL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CFR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CFR.bmp
new file mode 100644
index 000000000..4033764d8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CFR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CFS.bmp b/plugins/channelrx/demodadsb/airlinelogos/CFS.bmp
new file mode 100644
index 000000000..52b4787e0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CFS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CFV.bmp b/plugins/channelrx/demodadsb/airlinelogos/CFV.bmp
new file mode 100644
index 000000000..2e0c80e77
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CFV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CGE.bmp b/plugins/channelrx/demodadsb/airlinelogos/CGE.bmp
new file mode 100644
index 000000000..6ff6238d7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CGE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CGR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CGR.bmp
new file mode 100644
index 000000000..74f237a41
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CGR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CGZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CGZ.bmp
new file mode 100644
index 000000000..3cf3be87b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CGZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CHI.bmp b/plugins/channelrx/demodadsb/airlinelogos/CHI.bmp
new file mode 100644
index 000000000..1a79e6d05
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CHI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CHJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CHJ.bmp
new file mode 100644
index 000000000..6b0a006c9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CHJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CHQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CHQ.bmp
new file mode 100644
index 000000000..195c3c016
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CHQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CHR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CHR.bmp
new file mode 100644
index 000000000..fdc5355c0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CHR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/CIA.bmp
new file mode 100644
index 000000000..d5ff51946
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CIG.bmp b/plugins/channelrx/demodadsb/airlinelogos/CIG.bmp
new file mode 100644
index 000000000..930205fa2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CIG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CIL.bmp b/plugins/channelrx/demodadsb/airlinelogos/CIL.bmp
new file mode 100644
index 000000000..bf86318a0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CIL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CIN.bmp b/plugins/channelrx/demodadsb/airlinelogos/CIN.bmp
new file mode 100644
index 000000000..a0425dae8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CIN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CIT.bmp b/plugins/channelrx/demodadsb/airlinelogos/CIT.bmp
new file mode 100644
index 000000000..c57032a08
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CIT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CIV.bmp b/plugins/channelrx/demodadsb/airlinelogos/CIV.bmp
new file mode 100644
index 000000000..b19d36a11
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CIV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CJE.bmp b/plugins/channelrx/demodadsb/airlinelogos/CJE.bmp
new file mode 100644
index 000000000..0f71c7311
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CJE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CJL.bmp b/plugins/channelrx/demodadsb/airlinelogos/CJL.bmp
new file mode 100644
index 000000000..a9bb73060
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CJL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CJM.bmp b/plugins/channelrx/demodadsb/airlinelogos/CJM.bmp
new file mode 100644
index 000000000..d5e0d2f28
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CJM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CJR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CJR.bmp
new file mode 100644
index 000000000..4db042023
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CJR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CJT.bmp b/plugins/channelrx/demodadsb/airlinelogos/CJT.bmp
index 8e5210ad9..07dfad89a 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CJT.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CJT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CJX.bmp b/plugins/channelrx/demodadsb/airlinelogos/CJX.bmp
new file mode 100644
index 000000000..8c53c7dc2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CJX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CJZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CJZ.bmp
new file mode 100644
index 000000000..5e2c6856f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CJZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CKS.bmp b/plugins/channelrx/demodadsb/airlinelogos/CKS.bmp
index a0bac2b27..624c78c83 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CKS.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CKS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLB.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLB.bmp
new file mode 100644
index 000000000..f8eb0ebfb
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLD.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLD.bmp
new file mode 100644
index 000000000..52494c68d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLF.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLF.bmp
new file mode 100644
index 000000000..914664b22
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLH.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLH.bmp
new file mode 100644
index 000000000..51f9f1f5c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLN.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLN.bmp
new file mode 100644
index 000000000..90a720775
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLO.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLO.bmp
new file mode 100644
index 000000000..1c80e607d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLOUDGLOBAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLOUDGLOBAL.bmp
new file mode 100644
index 000000000..03e9ef2b9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLOUDGLOBAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLP.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLP.bmp
new file mode 100644
index 000000000..fd8379f80
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLU.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLU.bmp
new file mode 100644
index 000000000..6d4ee35ca
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLX.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLX.bmp
index 105cfc272..9c37bf1dd 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CLX.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CLX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CLY.bmp b/plugins/channelrx/demodadsb/airlinelogos/CLY.bmp
new file mode 100644
index 000000000..4940b7ce3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CLY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CMD.bmp b/plugins/channelrx/demodadsb/airlinelogos/CMD.bmp
new file mode 100644
index 000000000..8b9dc6419
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CMD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CME.bmp b/plugins/channelrx/demodadsb/airlinelogos/CME.bmp
new file mode 100644
index 000000000..23b402105
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CME.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CMP.bmp b/plugins/channelrx/demodadsb/airlinelogos/CMP.bmp
new file mode 100644
index 000000000..dccf62681
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CMP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CNA.bmp b/plugins/channelrx/demodadsb/airlinelogos/CNA.bmp
new file mode 100644
index 000000000..e0b69880b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CNA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CND.bmp b/plugins/channelrx/demodadsb/airlinelogos/CND.bmp
index 8eb512d9c..f09b829e2 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CND.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CND.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CNF.bmp b/plugins/channelrx/demodadsb/airlinelogos/CNF.bmp
new file mode 100644
index 000000000..cd12c152f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CNF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CNP.bmp b/plugins/channelrx/demodadsb/airlinelogos/CNP.bmp
new file mode 100644
index 000000000..829c0070b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CNP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CNW.bmp b/plugins/channelrx/demodadsb/airlinelogos/CNW.bmp
new file mode 100644
index 000000000..bc80cd01f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CNW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/COB.bmp b/plugins/channelrx/demodadsb/airlinelogos/COB.bmp
new file mode 100644
index 000000000..b3bda125f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/COB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/COL.bmp b/plugins/channelrx/demodadsb/airlinelogos/COL.bmp
new file mode 100644
index 000000000..8183eb0e6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/COL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CONa.bmp b/plugins/channelrx/demodadsb/airlinelogos/CONa.bmp
new file mode 100644
index 000000000..e6ebb572d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CONa.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/COO.bmp b/plugins/channelrx/demodadsb/airlinelogos/COO.bmp
new file mode 100644
index 000000000..1a8c9fda5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/COO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CORPORATEAIR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CORPORATEAIR.bmp
new file mode 100644
index 000000000..e381b241d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CORPORATEAIR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/COW.bmp b/plugins/channelrx/demodadsb/airlinelogos/COW.bmp
new file mode 100644
index 000000000..2478d1489
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/COW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/COY.bmp b/plugins/channelrx/demodadsb/airlinelogos/COY.bmp
new file mode 100644
index 000000000..8cbc6e940
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/COY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CPAC.bmp b/plugins/channelrx/demodadsb/airlinelogos/CPAC.bmp
new file mode 100644
index 000000000..806e9e5a6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CPAC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CPD.bmp b/plugins/channelrx/demodadsb/airlinelogos/CPD.bmp
new file mode 100644
index 000000000..322d01351
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CPD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CPE.bmp b/plugins/channelrx/demodadsb/airlinelogos/CPE.bmp
new file mode 100644
index 000000000..cc42374cb
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CPE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CPP.bmp b/plugins/channelrx/demodadsb/airlinelogos/CPP.bmp
new file mode 100644
index 000000000..65cdffcb8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CPP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CPS.bmp b/plugins/channelrx/demodadsb/airlinelogos/CPS.bmp
new file mode 100644
index 000000000..b90eddae0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CPS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CPV.bmp b/plugins/channelrx/demodadsb/airlinelogos/CPV.bmp
new file mode 100644
index 000000000..cbc3aadf8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CPV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CR.bmp
new file mode 100644
index 000000000..0cd0b9907
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CRA.bmp b/plugins/channelrx/demodadsb/airlinelogos/CRA.bmp
new file mode 100644
index 000000000..317a857b2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CRA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CRF.bmp b/plugins/channelrx/demodadsb/airlinelogos/CRF.bmp
new file mode 100644
index 000000000..0fbead529
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CRF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CRK.bmp b/plugins/channelrx/demodadsb/airlinelogos/CRK.bmp
new file mode 100644
index 000000000..0dc19fee1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CRK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CRN.bmp b/plugins/channelrx/demodadsb/airlinelogos/CRN.bmp
index 8cec12da8..0689ecc9d 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CRN.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CRN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CRNa.bmp b/plugins/channelrx/demodadsb/airlinelogos/CRNa.bmp
new file mode 100644
index 000000000..2329a0c1b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CRNa.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CRR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CRR.bmp
new file mode 100644
index 000000000..5875a5911
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CRR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CSB.bmp b/plugins/channelrx/demodadsb/airlinelogos/CSB.bmp
new file mode 100644
index 000000000..9ae6e8b93
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CSB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CSI.bmp b/plugins/channelrx/demodadsb/airlinelogos/CSI.bmp
new file mode 100644
index 000000000..bfe06013e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CSI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CSQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CSQ.bmp
new file mode 100644
index 000000000..978419814
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CSQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CST.bmp b/plugins/channelrx/demodadsb/airlinelogos/CST.bmp
new file mode 100644
index 000000000..d393ed0ee
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CST.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CSV.bmp b/plugins/channelrx/demodadsb/airlinelogos/CSV.bmp
new file mode 100644
index 000000000..767141781
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CSV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CTB.bmp b/plugins/channelrx/demodadsb/airlinelogos/CTB.bmp
new file mode 100644
index 000000000..eb931c92f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CTB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CTE.bmp b/plugins/channelrx/demodadsb/airlinelogos/CTE.bmp
new file mode 100644
index 000000000..245a93f37
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CTE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CTF.bmp b/plugins/channelrx/demodadsb/airlinelogos/CTF.bmp
new file mode 100644
index 000000000..b094919ca
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CTF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CTK.bmp b/plugins/channelrx/demodadsb/airlinelogos/CTK.bmp
new file mode 100644
index 000000000..61448d59f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CTK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CTV.bmp b/plugins/channelrx/demodadsb/airlinelogos/CTV.bmp
new file mode 100644
index 000000000..01156d5d2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CTV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CTW.bmp b/plugins/channelrx/demodadsb/airlinelogos/CTW.bmp
new file mode 100644
index 000000000..cf38a80f7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CTW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CUH.bmp b/plugins/channelrx/demodadsb/airlinelogos/CUH.bmp
new file mode 100644
index 000000000..b2c7ec571
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CUH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CUK.bmp b/plugins/channelrx/demodadsb/airlinelogos/CUK.bmp
new file mode 100644
index 000000000..722701e20
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CUK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CUL.bmp b/plugins/channelrx/demodadsb/airlinelogos/CUL.bmp
new file mode 100644
index 000000000..4badd803c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CUL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CVD.bmp b/plugins/channelrx/demodadsb/airlinelogos/CVD.bmp
new file mode 100644
index 000000000..799292a2f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CVD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CVE.bmp b/plugins/channelrx/demodadsb/airlinelogos/CVE.bmp
new file mode 100644
index 000000000..50b413694
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CVE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CVK.bmp b/plugins/channelrx/demodadsb/airlinelogos/CVK.bmp
new file mode 100644
index 000000000..e788cec0b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CVK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CVR.bmp b/plugins/channelrx/demodadsb/airlinelogos/CVR.bmp
new file mode 100644
index 000000000..dda08f649
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CVR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CVU.bmp b/plugins/channelrx/demodadsb/airlinelogos/CVU.bmp
new file mode 100644
index 000000000..756346078
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CVU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CVZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CVZ.bmp
new file mode 100644
index 000000000..27a19fd94
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CVZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CWA.bmp b/plugins/channelrx/demodadsb/airlinelogos/CWA.bmp
new file mode 100644
index 000000000..0f0141b57
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CWA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CWM.bmp b/plugins/channelrx/demodadsb/airlinelogos/CWM.bmp
new file mode 100644
index 000000000..790dfc952
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CWM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CWY.bmp b/plugins/channelrx/demodadsb/airlinelogos/CWY.bmp
new file mode 100644
index 000000000..4926e53ce
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CWY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CXB.bmp b/plugins/channelrx/demodadsb/airlinelogos/CXB.bmp
index f5d19fd99..e87e86b1f 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CXB.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CXB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CXE.bmp b/plugins/channelrx/demodadsb/airlinelogos/CXE.bmp
new file mode 100644
index 000000000..61921b35e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CXE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CXF.bmp b/plugins/channelrx/demodadsb/airlinelogos/CXF.bmp
new file mode 100644
index 000000000..ae3408ea2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CXF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CXI.bmp b/plugins/channelrx/demodadsb/airlinelogos/CXI.bmp
new file mode 100644
index 000000000..72afd5fad
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CXI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CXM.bmp b/plugins/channelrx/demodadsb/airlinelogos/CXM.bmp
new file mode 100644
index 000000000..d9807f39f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CXM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CXP.bmp b/plugins/channelrx/demodadsb/airlinelogos/CXP.bmp
new file mode 100644
index 000000000..3c5a3e3fb
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CXP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CYF.bmp b/plugins/channelrx/demodadsb/airlinelogos/CYF.bmp
new file mode 100644
index 000000000..3083f711e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CYF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CYL.bmp b/plugins/channelrx/demodadsb/airlinelogos/CYL.bmp
index 6e8766a39..1ce6f81e3 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CYL.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CYL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CYO.bmp b/plugins/channelrx/demodadsb/airlinelogos/CYO.bmp
new file mode 100644
index 000000000..a9e9f5aa2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CYO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CYP.bmp b/plugins/channelrx/demodadsb/airlinelogos/CYP.bmp
index 2624c030c..3acd7e5bb 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CYP.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CYP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CYT.bmp b/plugins/channelrx/demodadsb/airlinelogos/CYT.bmp
new file mode 100644
index 000000000..d4b5af223
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/CYT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/CYZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/CYZ.bmp
index 899568d82..340445c2a 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/CYZ.bmp and b/plugins/channelrx/demodadsb/airlinelogos/CYZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAB.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAB.bmp
new file mode 100644
index 000000000..38d0b1a68
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAE.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAE.bmp
new file mode 100644
index 000000000..603dcf85e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAF.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAF.bmp
new file mode 100644
index 000000000..da1e63da1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAILY.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAILY.bmp
new file mode 100644
index 000000000..e28d8a439
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAILY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAL.bmp
index 948928303..5992e5b27 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/DAL.bmp and b/plugins/channelrx/demodadsb/airlinelogos/DAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAN.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAN.bmp
new file mode 100644
index 000000000..1cbcf67de
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAO.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAO.bmp
index 32e08e04c..7744f7d1d 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/DAO.bmp and b/plugins/channelrx/demodadsb/airlinelogos/DAO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAR.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAR.bmp
new file mode 100644
index 000000000..96ebd60f0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAV.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAV.bmp
new file mode 100644
index 000000000..4e832439f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DAZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/DAZ.bmp
new file mode 100644
index 000000000..7bf4cce1a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DAZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DBC.bmp b/plugins/channelrx/demodadsb/airlinelogos/DBC.bmp
new file mode 100644
index 000000000..874db51b0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DBC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DCM.bmp b/plugins/channelrx/demodadsb/airlinelogos/DCM.bmp
new file mode 100644
index 000000000..64c28fabb
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DCM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DCT.bmp b/plugins/channelrx/demodadsb/airlinelogos/DCT.bmp
new file mode 100644
index 000000000..e0b3f3893
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DCT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DCW.bmp b/plugins/channelrx/demodadsb/airlinelogos/DCW.bmp
new file mode 100644
index 000000000..8fcb0eee6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DCW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DEJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/DEJ.bmp
new file mode 100644
index 000000000..dad37be0d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DEJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DET.bmp b/plugins/channelrx/demodadsb/airlinelogos/DET.bmp
new file mode 100644
index 000000000..c8b25f349
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DET.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DFL.bmp b/plugins/channelrx/demodadsb/airlinelogos/DFL.bmp
new file mode 100644
index 000000000..2e8bab41a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DFL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DGX.bmp b/plugins/channelrx/demodadsb/airlinelogos/DGX.bmp
new file mode 100644
index 000000000..2030765c2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DGX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHC.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHC.bmp
new file mode 100644
index 000000000..0c0d4ff11
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DHC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHE.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHE.bmp
new file mode 100644
index 000000000..e137a69f1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DHE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHK.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHK.bmp
new file mode 100644
index 000000000..603dcf85e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DHK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHR.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHR.bmp
new file mode 100644
index 000000000..fd6635d6b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DHR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHV.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHV.bmp
new file mode 100644
index 000000000..603dcf85e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DHV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHX.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHX.bmp
index 3508d9174..603dcf85e 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/DHX.bmp and b/plugins/channelrx/demodadsb/airlinelogos/DHX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DIG.bmp b/plugins/channelrx/demodadsb/airlinelogos/DIG.bmp
new file mode 100644
index 000000000..60297eda6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DIG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DIS.bmp b/plugins/channelrx/demodadsb/airlinelogos/DIS.bmp
new file mode 100644
index 000000000..08057a517
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DIS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DJC.bmp b/plugins/channelrx/demodadsb/airlinelogos/DJC.bmp
new file mode 100644
index 000000000..fe1208756
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DJC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DLH.bmp b/plugins/channelrx/demodadsb/airlinelogos/DLH.bmp
index 157454322..777e94999 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/DLH.bmp and b/plugins/channelrx/demodadsb/airlinelogos/DLH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DLX.bmp b/plugins/channelrx/demodadsb/airlinelogos/DLX.bmp
new file mode 100644
index 000000000..12657c11a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DLX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DLY.bmp b/plugins/channelrx/demodadsb/airlinelogos/DLY.bmp
new file mode 100644
index 000000000..f4961fce3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DLY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DMD.bmp b/plugins/channelrx/demodadsb/airlinelogos/DMD.bmp
new file mode 100644
index 000000000..07aad8f9f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DMD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DMN.bmp b/plugins/channelrx/demodadsb/airlinelogos/DMN.bmp
new file mode 100644
index 000000000..34c1a7a7f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DMN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DMS.bmp b/plugins/channelrx/demodadsb/airlinelogos/DMS.bmp
new file mode 100644
index 000000000..afe32e6ee
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DMS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DNC.bmp b/plugins/channelrx/demodadsb/airlinelogos/DNC.bmp
new file mode 100644
index 000000000..edf57a9ec
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DNC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DND.bmp b/plugins/channelrx/demodadsb/airlinelogos/DND.bmp
new file mode 100644
index 000000000..acef38074
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DND.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DNE.bmp b/plugins/channelrx/demodadsb/airlinelogos/DNE.bmp
new file mode 100644
index 000000000..932da8e79
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DNE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DNU.bmp b/plugins/channelrx/demodadsb/airlinelogos/DNU.bmp
new file mode 100644
index 000000000..db7df9f4f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DNU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DNY.bmp b/plugins/channelrx/demodadsb/airlinelogos/DNY.bmp
new file mode 100644
index 000000000..1eb740036
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DNY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DOC.bmp b/plugins/channelrx/demodadsb/airlinelogos/DOC.bmp
new file mode 100644
index 000000000..237a40162
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DOC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DOJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/DOJ.bmp
new file mode 100644
index 000000000..caa9608bd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DOJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DOK.bmp b/plugins/channelrx/demodadsb/airlinelogos/DOK.bmp
new file mode 100644
index 000000000..005332ed0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DOK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DOM.bmp b/plugins/channelrx/demodadsb/airlinelogos/DOM.bmp
new file mode 100644
index 000000000..0366d10d4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DOM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DOS.bmp b/plugins/channelrx/demodadsb/airlinelogos/DOS.bmp
new file mode 100644
index 000000000..079f25519
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DOS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DOW.bmp b/plugins/channelrx/demodadsb/airlinelogos/DOW.bmp
new file mode 100644
index 000000000..ae09f4af8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DOW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DPJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/DPJ.bmp
new file mode 100644
index 000000000..e53629405
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DPJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DQA.bmp b/plugins/channelrx/demodadsb/airlinelogos/DQA.bmp
new file mode 100644
index 000000000..96ef776c1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DQA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DRM.bmp b/plugins/channelrx/demodadsb/airlinelogos/DRM.bmp
new file mode 100644
index 000000000..c5a24b59c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DRM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DRZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/DRZ.bmp
new file mode 100644
index 000000000..5cfff1ff7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DRZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DSV.bmp b/plugins/channelrx/demodadsb/airlinelogos/DSV.bmp
new file mode 100644
index 000000000..42f072094
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DSV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DTO.bmp b/plugins/channelrx/demodadsb/airlinelogos/DTO.bmp
new file mode 100644
index 000000000..51987d081
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DTO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DVR.bmp b/plugins/channelrx/demodadsb/airlinelogos/DVR.bmp
new file mode 100644
index 000000000..e30d2a5a0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DVR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DWG.bmp b/plugins/channelrx/demodadsb/airlinelogos/DWG.bmp
new file mode 100644
index 000000000..4b2aa4d6c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DWG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DWI.bmp b/plugins/channelrx/demodadsb/airlinelogos/DWI.bmp
new file mode 100644
index 000000000..e5fdf6b53
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DWI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DYM.bmp b/plugins/channelrx/demodadsb/airlinelogos/DYM.bmp
new file mode 100644
index 000000000..0e33ca1a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DYM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DYN.bmp b/plugins/channelrx/demodadsb/airlinelogos/DYN.bmp
new file mode 100644
index 000000000..bddaf3848
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DYN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/DZR.bmp b/plugins/channelrx/demodadsb/airlinelogos/DZR.bmp
new file mode 100644
index 000000000..4a51c6e7a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/DZR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAD.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAD.bmp
new file mode 100644
index 000000000..d91fd0adf
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAF.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAF.bmp
new file mode 100644
index 000000000..57343a65e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAK.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAK.bmp
new file mode 100644
index 000000000..7d50fd29a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAL.bmp
index 3b20bc658..b4d730864 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/EAL.bmp and b/plugins/channelrx/demodadsb/airlinelogos/EAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EALOLD.bmp b/plugins/channelrx/demodadsb/airlinelogos/EALOLD.bmp
new file mode 100644
index 000000000..3b20bc658
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EALOLD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAP.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAP.bmp
new file mode 100644
index 000000000..83a784172
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAT.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAT.bmp
new file mode 100644
index 000000000..003987832
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAU.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAU.bmp
new file mode 100644
index 000000000..13a13e539
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAW.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAW.bmp
new file mode 100644
index 000000000..362f6ab26
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EAX.bmp b/plugins/channelrx/demodadsb/airlinelogos/EAX.bmp
new file mode 100644
index 000000000..a9ecedb4e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EAX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EBF.bmp b/plugins/channelrx/demodadsb/airlinelogos/EBF.bmp
new file mode 100644
index 000000000..e58a3dd06
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EBF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EBS.bmp b/plugins/channelrx/demodadsb/airlinelogos/EBS.bmp
new file mode 100644
index 000000000..70c51ec6d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EBS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EBV.bmp b/plugins/channelrx/demodadsb/airlinelogos/EBV.bmp
new file mode 100644
index 000000000..b7f001f53
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EBV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ECA.bmp b/plugins/channelrx/demodadsb/airlinelogos/ECA.bmp
new file mode 100644
index 000000000..6422a839b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ECA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ECC.bmp b/plugins/channelrx/demodadsb/airlinelogos/ECC.bmp
new file mode 100644
index 000000000..6f1b07f8a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ECC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EDC.bmp b/plugins/channelrx/demodadsb/airlinelogos/EDC.bmp
new file mode 100644
index 000000000..1bd7f3a1c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EDC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EDG.bmp b/plugins/channelrx/demodadsb/airlinelogos/EDG.bmp
new file mode 100644
index 000000000..1956a35f0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EDG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EDR.bmp b/plugins/channelrx/demodadsb/airlinelogos/EDR.bmp
new file mode 100644
index 000000000..7ca839a31
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EDR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EDV.bmp b/plugins/channelrx/demodadsb/airlinelogos/EDV.bmp
new file mode 100644
index 000000000..a4ce8c1b7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EDV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EDW.bmp b/plugins/channelrx/demodadsb/airlinelogos/EDW.bmp
new file mode 100644
index 000000000..6be1e613e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EDW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EDY.bmp b/plugins/channelrx/demodadsb/airlinelogos/EDY.bmp
new file mode 100644
index 000000000..baf5511da
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EDY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EEL.bmp b/plugins/channelrx/demodadsb/airlinelogos/EEL.bmp
new file mode 100644
index 000000000..a3bae7e9e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EEL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EES.bmp b/plugins/channelrx/demodadsb/airlinelogos/EES.bmp
new file mode 100644
index 000000000..e3738ad23
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EES.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EEU.bmp b/plugins/channelrx/demodadsb/airlinelogos/EEU.bmp
new file mode 100644
index 000000000..bf4480ec0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EEU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EFA.bmp b/plugins/channelrx/demodadsb/airlinelogos/EFA.bmp
new file mode 100644
index 000000000..f04d6a79b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EFA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EFD.bmp b/plugins/channelrx/demodadsb/airlinelogos/EFD.bmp
new file mode 100644
index 000000000..d55cae532
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EFD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EFF.bmp b/plugins/channelrx/demodadsb/airlinelogos/EFF.bmp
new file mode 100644
index 000000000..bbaf2c2bd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EFF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EFG.bmp b/plugins/channelrx/demodadsb/airlinelogos/EFG.bmp
new file mode 100644
index 000000000..bec05376b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EFG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EFT.bmp b/plugins/channelrx/demodadsb/airlinelogos/EFT.bmp
new file mode 100644
index 000000000..d993c5482
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EFT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EFX.bmp b/plugins/channelrx/demodadsb/airlinelogos/EFX.bmp
new file mode 100644
index 000000000..464549ccf
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EFX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EGJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/EGJ.bmp
new file mode 100644
index 000000000..f81e05a35
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EGJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EGL.bmp b/plugins/channelrx/demodadsb/airlinelogos/EGL.bmp
new file mode 100644
index 000000000..c47ca4998
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EGL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EGS.bmp b/plugins/channelrx/demodadsb/airlinelogos/EGS.bmp
new file mode 100644
index 000000000..63e470bb4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EGS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EGU.bmp b/plugins/channelrx/demodadsb/airlinelogos/EGU.bmp
new file mode 100644
index 000000000..dfa00e319
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EGU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EGW.bmp b/plugins/channelrx/demodadsb/airlinelogos/EGW.bmp
new file mode 100644
index 000000000..e517fb759
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EGW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EHR.bmp b/plugins/channelrx/demodadsb/airlinelogos/EHR.bmp
new file mode 100644
index 000000000..4639b20d2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EHR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EIN.bmp b/plugins/channelrx/demodadsb/airlinelogos/EIN.bmp
new file mode 100644
index 000000000..56711aaf2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EIN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EINREA.bmp b/plugins/channelrx/demodadsb/airlinelogos/EINREA.bmp
new file mode 100644
index 000000000..20eff418e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EINREA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EIS.bmp b/plugins/channelrx/demodadsb/airlinelogos/EIS.bmp
new file mode 100644
index 000000000..e5a4d54f7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EIS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EJA.bmp b/plugins/channelrx/demodadsb/airlinelogos/EJA.bmp
new file mode 100644
index 000000000..0667656c0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EJA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EJE.bmp b/plugins/channelrx/demodadsb/airlinelogos/EJE.bmp
new file mode 100644
index 000000000..f2b39ce07
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EJE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EJM.bmp b/plugins/channelrx/demodadsb/airlinelogos/EJM.bmp
new file mode 100644
index 000000000..bfc5218c8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EJM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EJO.bmp b/plugins/channelrx/demodadsb/airlinelogos/EJO.bmp
new file mode 100644
index 000000000..e903b6c44
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EJO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EJT.bmp b/plugins/channelrx/demodadsb/airlinelogos/EJT.bmp
new file mode 100644
index 000000000..d2c52b0d5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EJT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EJU.bmp b/plugins/channelrx/demodadsb/airlinelogos/EJU.bmp
new file mode 100644
index 000000000..309028a90
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EJU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EKY.bmp b/plugins/channelrx/demodadsb/airlinelogos/EKY.bmp
new file mode 100644
index 000000000..bd60960f7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EKY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELB.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELB.bmp
new file mode 100644
index 000000000..eba0fa845
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELE.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELE.bmp
new file mode 100644
index 000000000..9f7cdaf12
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELF.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELF.bmp
new file mode 100644
index 000000000..5494848a7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELH.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELH.bmp
new file mode 100644
index 000000000..c70212158
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELJ.bmp
new file mode 100644
index 000000000..232a2722c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELP.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELP.bmp
new file mode 100644
index 000000000..8a97af6b8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELT.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELT.bmp
new file mode 100644
index 000000000..ad5bc1601
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELW.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELW.bmp
new file mode 100644
index 000000000..ed52d25f4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ELY.bmp b/plugins/channelrx/demodadsb/airlinelogos/ELY.bmp
new file mode 100644
index 000000000..6973d3b67
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ELY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EML.bmp b/plugins/channelrx/demodadsb/airlinelogos/EML.bmp
new file mode 100644
index 000000000..508f8e2f3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EML.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EMM.bmp b/plugins/channelrx/demodadsb/airlinelogos/EMM.bmp
new file mode 100644
index 000000000..714b5d49e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EMM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EMT.bmp b/plugins/channelrx/demodadsb/airlinelogos/EMT.bmp
new file mode 100644
index 000000000..c4506ea1f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EMT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ENF.bmp b/plugins/channelrx/demodadsb/airlinelogos/ENF.bmp
new file mode 100644
index 000000000..745ab659e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ENF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ENJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/ENJ.bmp
index 768f050b3..5c9fc0b6a 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/ENJ.bmp and b/plugins/channelrx/demodadsb/airlinelogos/ENJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ENK.bmp b/plugins/channelrx/demodadsb/airlinelogos/ENK.bmp
new file mode 100644
index 000000000..ece7e4da2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ENK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ENW.bmp b/plugins/channelrx/demodadsb/airlinelogos/ENW.bmp
new file mode 100644
index 000000000..6796a00fe
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ENW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ENY.bmp b/plugins/channelrx/demodadsb/airlinelogos/ENY.bmp
new file mode 100644
index 000000000..3e5555147
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ENY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EOA.bmp b/plugins/channelrx/demodadsb/airlinelogos/EOA.bmp
new file mode 100644
index 000000000..a4e7722d0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EOA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EOK.bmp b/plugins/channelrx/demodadsb/airlinelogos/EOK.bmp
new file mode 100644
index 000000000..f94553225
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EOK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EPC.bmp b/plugins/channelrx/demodadsb/airlinelogos/EPC.bmp
new file mode 100644
index 000000000..99dab36a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EPC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EPJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/EPJ.bmp
new file mode 100644
index 000000000..cc1930a57
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EPJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EPR.bmp b/plugins/channelrx/demodadsb/airlinelogos/EPR.bmp
new file mode 100644
index 000000000..1cbdf85c4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EPR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERA.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERA.bmp
new file mode 100644
index 000000000..4cdf2a967
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ERA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERF.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERF.bmp
new file mode 100644
index 000000000..edbe4b215
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ERF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERK.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERK.bmp
new file mode 100644
index 000000000..715c5db9b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ERK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERN.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERN.bmp
new file mode 100644
index 000000000..71cbb5936
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ERN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERO.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERO.bmp
new file mode 100644
index 000000000..c3fddebea
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ERO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERR.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERR.bmp
new file mode 100644
index 000000000..6a0a113a3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ERR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERT.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERT.bmp
index 648daf7ab..85db86a3a 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/ERT.bmp and b/plugins/channelrx/demodadsb/airlinelogos/ERT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ERY.bmp b/plugins/channelrx/demodadsb/airlinelogos/ERY.bmp
new file mode 100644
index 000000000..b696a4de7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ERY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ESF.bmp b/plugins/channelrx/demodadsb/airlinelogos/ESF.bmp
new file mode 100644
index 000000000..e5e7e6e8c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ESF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ESJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/ESJ.bmp
new file mode 100644
index 000000000..5f7ea87ae
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ESJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ESR.bmp b/plugins/channelrx/demodadsb/airlinelogos/ESR.bmp
new file mode 100644
index 000000000..d1880079f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ESR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EST.bmp b/plugins/channelrx/demodadsb/airlinelogos/EST.bmp
new file mode 100644
index 000000000..926c8fca3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EST.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ESW.bmp b/plugins/channelrx/demodadsb/airlinelogos/ESW.bmp
new file mode 100644
index 000000000..1d11b8fbb
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ESW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ETA.bmp b/plugins/channelrx/demodadsb/airlinelogos/ETA.bmp
new file mode 100644
index 000000000..001a01648
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ETA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ETI.bmp b/plugins/channelrx/demodadsb/airlinelogos/ETI.bmp
new file mode 100644
index 000000000..165bb1180
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ETI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ETP.bmp b/plugins/channelrx/demodadsb/airlinelogos/ETP.bmp
new file mode 100644
index 000000000..366efc636
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ETP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ETR.bmp b/plugins/channelrx/demodadsb/airlinelogos/ETR.bmp
new file mode 100644
index 000000000..ad0f3e486
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ETR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EUC.bmp b/plugins/channelrx/demodadsb/airlinelogos/EUC.bmp
new file mode 100644
index 000000000..870256b60
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EUC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EUL.bmp b/plugins/channelrx/demodadsb/airlinelogos/EUL.bmp
new file mode 100644
index 000000000..bbe2a6714
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EUL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EUS.bmp b/plugins/channelrx/demodadsb/airlinelogos/EUS.bmp
new file mode 100644
index 000000000..1e9b6ba8c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EUS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EUW.bmp b/plugins/channelrx/demodadsb/airlinelogos/EUW.bmp
new file mode 100644
index 000000000..66a5b2c7e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EUW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EVE.bmp b/plugins/channelrx/demodadsb/airlinelogos/EVE.bmp
new file mode 100644
index 000000000..699324af5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EVE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EVJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/EVJ.bmp
new file mode 100644
index 000000000..cc45b4c7c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EVJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EVK.bmp b/plugins/channelrx/demodadsb/airlinelogos/EVK.bmp
new file mode 100644
index 000000000..f95d00ca5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EVK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EVL.bmp b/plugins/channelrx/demodadsb/airlinelogos/EVL.bmp
new file mode 100644
index 000000000..639327096
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EVL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EVQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/EVQ.bmp
new file mode 100644
index 000000000..f95d00ca5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EVQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EVX.bmp b/plugins/channelrx/demodadsb/airlinelogos/EVX.bmp
new file mode 100644
index 000000000..be6f18452
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EVX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EVY.bmp b/plugins/channelrx/demodadsb/airlinelogos/EVY.bmp
new file mode 100644
index 000000000..cd386201c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EVY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EWE.bmp b/plugins/channelrx/demodadsb/airlinelogos/EWE.bmp
new file mode 100644
index 000000000..22bddd901
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EWE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EWF.bmp b/plugins/channelrx/demodadsb/airlinelogos/EWF.bmp
new file mode 100644
index 000000000..61385ea10
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EWF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EWR.bmp b/plugins/channelrx/demodadsb/airlinelogos/EWR.bmp
new file mode 100644
index 000000000..6a6d4509a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EWR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EWS.bmp b/plugins/channelrx/demodadsb/airlinelogos/EWS.bmp
new file mode 100644
index 000000000..9ff068b71
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EWS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXA.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXA.bmp
new file mode 100644
index 000000000..75a7e3573
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXC.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXC.bmp
new file mode 100644
index 000000000..213149f9c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXH.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXH.bmp
new file mode 100644
index 000000000..629711417
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXN.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXN.bmp
new file mode 100644
index 000000000..0cce9d2a8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXP.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXP.bmp
new file mode 100644
index 000000000..011b135bd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXSa.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXSa.bmp
new file mode 100644
index 000000000..0d9a13522
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXSa.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXU.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXU.bmp
new file mode 100644
index 000000000..a9855cff3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXV.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXV.bmp
new file mode 100644
index 000000000..2b1f3d84d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXY.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXY.bmp
new file mode 100644
index 000000000..8621b3072
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EXZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/EXZ.bmp
new file mode 100644
index 000000000..f55529949
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EXZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EYC.bmp b/plugins/channelrx/demodadsb/airlinelogos/EYC.bmp
new file mode 100644
index 000000000..ffa1fd6ed
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EYC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EZB.bmp b/plugins/channelrx/demodadsb/airlinelogos/EZB.bmp
new file mode 100644
index 000000000..5b4437625
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EZB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EZE.bmp b/plugins/channelrx/demodadsb/airlinelogos/EZE.bmp
index 438863bc7..d1c970f2d 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/EZE.bmp and b/plugins/channelrx/demodadsb/airlinelogos/EZE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/EZS.bmp b/plugins/channelrx/demodadsb/airlinelogos/EZS.bmp
new file mode 100644
index 000000000..8b43603a0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/EZS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FAB.bmp b/plugins/channelrx/demodadsb/airlinelogos/FAB.bmp
index b4a388d1f..e884f8abc 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/FAB.bmp and b/plugins/channelrx/demodadsb/airlinelogos/FAB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FAD.bmp b/plugins/channelrx/demodadsb/airlinelogos/FAD.bmp
new file mode 100644
index 000000000..4f039be8d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FAD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FBA.bmp b/plugins/channelrx/demodadsb/airlinelogos/FBA.bmp
new file mode 100644
index 000000000..02185cdb9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FBA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FBB.bmp b/plugins/channelrx/demodadsb/airlinelogos/FBB.bmp
new file mode 100644
index 000000000..80fdf2326
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FBB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FBD.bmp b/plugins/channelrx/demodadsb/airlinelogos/FBD.bmp
index 967f59a28..746721036 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/FBD.bmp and b/plugins/channelrx/demodadsb/airlinelogos/FBD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FBU.bmp b/plugins/channelrx/demodadsb/airlinelogos/FBU.bmp
new file mode 100644
index 000000000..d6763d1e4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FBU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FC.bmp b/plugins/channelrx/demodadsb/airlinelogos/FC.bmp
new file mode 100644
index 000000000..c18c84a8f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FCM.bmp b/plugins/channelrx/demodadsb/airlinelogos/FCM.bmp
index fe6cec099..e116c670a 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/FCM.bmp and b/plugins/channelrx/demodadsb/airlinelogos/FCM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FDA.bmp b/plugins/channelrx/demodadsb/airlinelogos/FDA.bmp
new file mode 100644
index 000000000..e9e0c99e8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FDA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FDJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/FDJ.bmp
new file mode 100644
index 000000000..03157ca75
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FDJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FDT.bmp b/plugins/channelrx/demodadsb/airlinelogos/FDT.bmp
new file mode 100644
index 000000000..1203c9c97
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FDT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FDY.bmp b/plugins/channelrx/demodadsb/airlinelogos/FDY.bmp
new file mode 100644
index 000000000..1ae7cb73b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FDY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FEA.bmp b/plugins/channelrx/demodadsb/airlinelogos/FEA.bmp
new file mode 100644
index 000000000..b3ec5622e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FEA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FEG.bmp b/plugins/channelrx/demodadsb/airlinelogos/FEG.bmp
new file mode 100644
index 000000000..1576a58bf
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FEG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FEI.bmp b/plugins/channelrx/demodadsb/airlinelogos/FEI.bmp
new file mode 100644
index 000000000..29f7560c3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FEI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FFL.bmp b/plugins/channelrx/demodadsb/airlinelogos/FFL.bmp
new file mode 100644
index 000000000..61e1f8bf6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FFL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FFM.bmp b/plugins/channelrx/demodadsb/airlinelogos/FFM.bmp
new file mode 100644
index 000000000..9a73a5214
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FFM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FGW.bmp b/plugins/channelrx/demodadsb/airlinelogos/FGW.bmp
new file mode 100644
index 000000000..d7f792912
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FGW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/FIA.bmp
new file mode 100644
index 000000000..d101b3787
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FJR.bmp b/plugins/channelrx/demodadsb/airlinelogos/FJR.bmp
new file mode 100644
index 000000000..374700a9d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FJR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FJW.bmp b/plugins/channelrx/demodadsb/airlinelogos/FJW.bmp
new file mode 100644
index 000000000..e615874f3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FJW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FLE.bmp b/plugins/channelrx/demodadsb/airlinelogos/FLE.bmp
index 0f1088644..5a4cc3328 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/FLE.bmp and b/plugins/channelrx/demodadsb/airlinelogos/FLE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FLEXIFLY.bmp b/plugins/channelrx/demodadsb/airlinelogos/FLEXIFLY.bmp
new file mode 100644
index 000000000..e064948a3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FLEXIFLY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FLO.bmp b/plugins/channelrx/demodadsb/airlinelogos/FLO.bmp
new file mode 100644
index 000000000..7c3b5f405
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FLO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FLYPELICAN.bmp b/plugins/channelrx/demodadsb/airlinelogos/FLYPELICAN.bmp
new file mode 100644
index 000000000..ecb700045
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FLYPELICAN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FRG.bmp b/plugins/channelrx/demodadsb/airlinelogos/FRG.bmp
new file mode 100644
index 000000000..edbe55d39
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FRG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FRH.bmp b/plugins/channelrx/demodadsb/airlinelogos/FRH.bmp
new file mode 100644
index 000000000..44a5c63f6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FRH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FSQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/FSQ.bmp
new file mode 100644
index 000000000..86a31968a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FSQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FSY.bmp b/plugins/channelrx/demodadsb/airlinelogos/FSY.bmp
new file mode 100644
index 000000000..beda2adf2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FSY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FTH.bmp b/plugins/channelrx/demodadsb/airlinelogos/FTH.bmp
new file mode 100644
index 000000000..44ccef286
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FTH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FTO.bmp b/plugins/channelrx/demodadsb/airlinelogos/FTO.bmp
new file mode 100644
index 000000000..35d900d53
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FTO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FXP.bmp b/plugins/channelrx/demodadsb/airlinelogos/FXP.bmp
new file mode 100644
index 000000000..566910cbd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FXP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FXX.bmp b/plugins/channelrx/demodadsb/airlinelogos/FXX.bmp
new file mode 100644
index 000000000..3390f3e43
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FXX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/FYL.bmp b/plugins/channelrx/demodadsb/airlinelogos/FYL.bmp
new file mode 100644
index 000000000..a56946e92
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/FYL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GAJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/GAJ.bmp
new file mode 100644
index 000000000..0c53ee2f3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GAJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/GAL.bmp
new file mode 100644
index 000000000..7d5080901
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GBB.bmp b/plugins/channelrx/demodadsb/airlinelogos/GBB.bmp
new file mode 100644
index 000000000..88ce2ddb3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GBB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GCL.bmp b/plugins/channelrx/demodadsb/airlinelogos/GCL.bmp
new file mode 100644
index 000000000..eb5df58c8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GCL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GCT.bmp b/plugins/channelrx/demodadsb/airlinelogos/GCT.bmp
new file mode 100644
index 000000000..7fe059395
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GCT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GDE.bmp b/plugins/channelrx/demodadsb/airlinelogos/GDE.bmp
new file mode 100644
index 000000000..73a145659
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GDE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GJE.bmp b/plugins/channelrx/demodadsb/airlinelogos/GJE.bmp
new file mode 100644
index 000000000..453a94cf1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GJE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GJI.bmp b/plugins/channelrx/demodadsb/airlinelogos/GJI.bmp
new file mode 100644
index 000000000..0c1a95b68
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GJI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GJM.bmp b/plugins/channelrx/demodadsb/airlinelogos/GJM.bmp
new file mode 100644
index 000000000..f455dd5e8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GJM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GJS.bmp b/plugins/channelrx/demodadsb/airlinelogos/GJS.bmp
new file mode 100644
index 000000000..24d9efd80
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GJS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GJT.bmp b/plugins/channelrx/demodadsb/airlinelogos/GJT.bmp
new file mode 100644
index 000000000..f455dd5e8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GJT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GLO.bmp b/plugins/channelrx/demodadsb/airlinelogos/GLO.bmp
index a47fa0f2c..8410dc0ce 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/GLO.bmp and b/plugins/channelrx/demodadsb/airlinelogos/GLO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GMR.bmp b/plugins/channelrx/demodadsb/airlinelogos/GMR.bmp
new file mode 100644
index 000000000..d309ddc90
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GMR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GOW.bmp b/plugins/channelrx/demodadsb/airlinelogos/GOW.bmp
index 04d0fe105..b708fb58d 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/GOW.bmp and b/plugins/channelrx/demodadsb/airlinelogos/GOW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GSW.bmp b/plugins/channelrx/demodadsb/airlinelogos/GSW.bmp
new file mode 100644
index 000000000..1c6fd76d5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GSW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GTR.bmp b/plugins/channelrx/demodadsb/airlinelogos/GTR.bmp
new file mode 100644
index 000000000..f060c0ffc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/GTR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/GTV.bmp b/plugins/channelrx/demodadsb/airlinelogos/GTV.bmp
index c53b033c9..165b08eba 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/GTV.bmp and b/plugins/channelrx/demodadsb/airlinelogos/GTV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HGG.bmp b/plugins/channelrx/demodadsb/airlinelogos/HGG.bmp
new file mode 100644
index 000000000..1ce8e821e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HGG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HHN.bmp b/plugins/channelrx/demodadsb/airlinelogos/HHN.bmp
new file mode 100644
index 000000000..29e8630b0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HHN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HIM.bmp b/plugins/channelrx/demodadsb/airlinelogos/HIM.bmp
new file mode 100644
index 000000000..34d57c72a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HIM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HKC.bmp b/plugins/channelrx/demodadsb/airlinelogos/HKC.bmp
new file mode 100644
index 000000000..44a198105
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HKC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HKH.bmp b/plugins/channelrx/demodadsb/airlinelogos/HKH.bmp
new file mode 100644
index 000000000..a4e18737a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HKH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HKS.bmp b/plugins/channelrx/demodadsb/airlinelogos/HKS.bmp
new file mode 100644
index 000000000..d188bc8df
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HKS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HLE.bmp b/plugins/channelrx/demodadsb/airlinelogos/HLE.bmp
new file mode 100644
index 000000000..25715121e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HLE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HLF.bmp b/plugins/channelrx/demodadsb/airlinelogos/HLF.bmp
new file mode 100644
index 000000000..fafc6cb68
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HLF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HLL.bmp b/plugins/channelrx/demodadsb/airlinelogos/HLL.bmp
new file mode 100644
index 000000000..7ac98d730
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HLL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HLLa.bmp b/plugins/channelrx/demodadsb/airlinelogos/HLLa.bmp
new file mode 100644
index 000000000..4383731cc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HLLa.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HND.bmp b/plugins/channelrx/demodadsb/airlinelogos/HND.bmp
new file mode 100644
index 000000000..0d2beb578
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HND.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HNW.bmp b/plugins/channelrx/demodadsb/airlinelogos/HNW.bmp
new file mode 100644
index 000000000..99f57ba23
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HNW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HRT.bmp b/plugins/channelrx/demodadsb/airlinelogos/HRT.bmp
new file mode 100644
index 000000000..5d29e1cbe
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HRT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HTS.bmp b/plugins/channelrx/demodadsb/airlinelogos/HTS.bmp
new file mode 100644
index 000000000..1b3cbea79
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HTS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HTU.bmp b/plugins/channelrx/demodadsb/airlinelogos/HTU.bmp
new file mode 100644
index 000000000..5c58b7d34
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HTU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HWA.bmp b/plugins/channelrx/demodadsb/airlinelogos/HWA.bmp
new file mode 100644
index 000000000..1a97f1c3a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HWA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HYA.bmp b/plugins/channelrx/demodadsb/airlinelogos/HYA.bmp
new file mode 100644
index 000000000..5d0dfbd03
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HYA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HYP.bmp b/plugins/channelrx/demodadsb/airlinelogos/HYP.bmp
new file mode 100644
index 000000000..9dc4bf228
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HYP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HYT.bmp b/plugins/channelrx/demodadsb/airlinelogos/HYT.bmp
new file mode 100644
index 000000000..b7a409531
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HYT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/HZS.bmp b/plugins/channelrx/demodadsb/airlinelogos/HZS.bmp
new file mode 100644
index 000000000..1c798c32f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/HZS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IAE.bmp b/plugins/channelrx/demodadsb/airlinelogos/IAE.bmp
new file mode 100644
index 000000000..24bab4472
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IAE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IAX.bmp b/plugins/channelrx/demodadsb/airlinelogos/IAX.bmp
new file mode 100644
index 000000000..d5f6c9746
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IAX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IBX.bmp b/plugins/channelrx/demodadsb/airlinelogos/IBX.bmp
new file mode 100644
index 000000000..9c43afa29
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IBX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ICL.bmp b/plugins/channelrx/demodadsb/airlinelogos/ICL.bmp
new file mode 100644
index 000000000..79d0d013d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ICL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ICV.bmp b/plugins/channelrx/demodadsb/airlinelogos/ICV.bmp
new file mode 100644
index 000000000..2441339e6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ICV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IFL.bmp b/plugins/channelrx/demodadsb/airlinelogos/IFL.bmp
new file mode 100644
index 000000000..113d0903f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IFL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IGA.bmp b/plugins/channelrx/demodadsb/airlinelogos/IGA.bmp
index 861b363ce..5cea9cdc9 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/IGA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/IGA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IHO.bmp b/plugins/channelrx/demodadsb/airlinelogos/IHO.bmp
new file mode 100644
index 000000000..1ff6c17b6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IHO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/IIA.bmp
new file mode 100644
index 000000000..aa0f1252c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IKA.bmp b/plugins/channelrx/demodadsb/airlinelogos/IKA.bmp
new file mode 100644
index 000000000..d02036f5f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IKA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IMX.bmp b/plugins/channelrx/demodadsb/airlinelogos/IMX.bmp
new file mode 100644
index 000000000..357a6a2df
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IMX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IOS.bmp b/plugins/channelrx/demodadsb/airlinelogos/IOS.bmp
new file mode 100644
index 000000000..d604b7ffb
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IOS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IRB.bmp b/plugins/channelrx/demodadsb/airlinelogos/IRB.bmp
new file mode 100644
index 000000000..9e97be2b4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IRB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ISR.bmp b/plugins/channelrx/demodadsb/airlinelogos/ISR.bmp
new file mode 100644
index 000000000..e920884e0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ISR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IWY.bmp b/plugins/channelrx/demodadsb/airlinelogos/IWY.bmp
new file mode 100644
index 000000000..89052bfb8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IWY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IXR.bmp b/plugins/channelrx/demodadsb/airlinelogos/IXR.bmp
new file mode 100644
index 000000000..9a271d15e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IXR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IYA.bmp b/plugins/channelrx/demodadsb/airlinelogos/IYA.bmp
new file mode 100644
index 000000000..bcce05026
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IYA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IZA.bmp b/plugins/channelrx/demodadsb/airlinelogos/IZA.bmp
new file mode 100644
index 000000000..8dde12811
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IZA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/IZG.bmp b/plugins/channelrx/demodadsb/airlinelogos/IZG.bmp
new file mode 100644
index 000000000..526e5798f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/IZG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/JAL.bmp
new file mode 100644
index 000000000..2673fa167
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JAS.bmp b/plugins/channelrx/demodadsb/airlinelogos/JAS.bmp
new file mode 100644
index 000000000..1a951b88b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JAS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JAT.bmp b/plugins/channelrx/demodadsb/airlinelogos/JAT.bmp
index c94edf204..e1a1c469c 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/JAT.bmp and b/plugins/channelrx/demodadsb/airlinelogos/JAT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JBE.bmp b/plugins/channelrx/demodadsb/airlinelogos/JBE.bmp
new file mode 100644
index 000000000..f3d194a2f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JBE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JCL.bmp b/plugins/channelrx/demodadsb/airlinelogos/JCL.bmp
new file mode 100644
index 000000000..74c2defc7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JCL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JCM.bmp b/plugins/channelrx/demodadsb/airlinelogos/JCM.bmp
new file mode 100644
index 000000000..f6ce80ff6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JCM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JEI.bmp b/plugins/channelrx/demodadsb/airlinelogos/JEI.bmp
new file mode 100644
index 000000000..c074d79e4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JEI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JES.bmp b/plugins/channelrx/demodadsb/airlinelogos/JES.bmp
new file mode 100644
index 000000000..e1a1c469c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JES.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JFL.bmp b/plugins/channelrx/demodadsb/airlinelogos/JFL.bmp
new file mode 100644
index 000000000..b9bf195c4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JFL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/JIA.bmp
new file mode 100644
index 000000000..9050b628d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JJA.bmp b/plugins/channelrx/demodadsb/airlinelogos/JJA.bmp
new file mode 100644
index 000000000..256087ca2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JJA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JJP.bmp b/plugins/channelrx/demodadsb/airlinelogos/JJP.bmp
new file mode 100644
index 000000000..4c6778c43
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JJP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JKR.bmp b/plugins/channelrx/demodadsb/airlinelogos/JKR.bmp
new file mode 100644
index 000000000..8d807c536
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JKR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JLF.bmp b/plugins/channelrx/demodadsb/airlinelogos/JLF.bmp
new file mode 100644
index 000000000..b839794a9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JLF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JMA.bmp b/plugins/channelrx/demodadsb/airlinelogos/JMA.bmp
new file mode 100644
index 000000000..929a8b694
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JMA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JME.bmp b/plugins/channelrx/demodadsb/airlinelogos/JME.bmp
new file mode 100644
index 000000000..200a6af77
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JME.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JML.bmp b/plugins/channelrx/demodadsb/airlinelogos/JML.bmp
new file mode 100644
index 000000000..c41c1913a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JML.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JNL.bmp b/plugins/channelrx/demodadsb/airlinelogos/JNL.bmp
new file mode 100644
index 000000000..de99bac1c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JNL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JON.bmp b/plugins/channelrx/demodadsb/airlinelogos/JON.bmp
new file mode 100644
index 000000000..072e09314
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JON.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JRC.bmp b/plugins/channelrx/demodadsb/airlinelogos/JRC.bmp
new file mode 100644
index 000000000..9ce60b3e1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JRC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JRT.bmp b/plugins/channelrx/demodadsb/airlinelogos/JRT.bmp
new file mode 100644
index 000000000..df7c0ac32
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JRT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JSY.bmp b/plugins/channelrx/demodadsb/airlinelogos/JSY.bmp
new file mode 100644
index 000000000..b8681668e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JSY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JTA.bmp b/plugins/channelrx/demodadsb/airlinelogos/JTA.bmp
new file mode 100644
index 000000000..9c2da89fc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/JTA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/JYH.bmp b/plugins/channelrx/demodadsb/airlinelogos/JYH.bmp
index 493deda69..acf34d1b0 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/JYH.bmp and b/plugins/channelrx/demodadsb/airlinelogos/JYH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KAC.bmp b/plugins/channelrx/demodadsb/airlinelogos/KAC.bmp
index b83202f6e..0648b73bf 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/KAC.bmp and b/plugins/channelrx/demodadsb/airlinelogos/KAC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KAP.bmp b/plugins/channelrx/demodadsb/airlinelogos/KAP.bmp
new file mode 100644
index 000000000..d0ae4dd5e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KAP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KAR.bmp b/plugins/channelrx/demodadsb/airlinelogos/KAR.bmp
new file mode 100644
index 000000000..d22e8cdde
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KAR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KAZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/KAZ.bmp
new file mode 100644
index 000000000..42f8ee076
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KAZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KBZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/KBZ.bmp
new file mode 100644
index 000000000..d842d9c9f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KBZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KDS.bmp b/plugins/channelrx/demodadsb/airlinelogos/KDS.bmp
new file mode 100644
index 000000000..291821f1a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KDS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KEM.bmp b/plugins/channelrx/demodadsb/airlinelogos/KEM.bmp
new file mode 100644
index 000000000..14dc0c7f7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KEM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KEN.bmp b/plugins/channelrx/demodadsb/airlinelogos/KEN.bmp
new file mode 100644
index 000000000..1d24ac8c7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KEN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KFE.bmp b/plugins/channelrx/demodadsb/airlinelogos/KFE.bmp
new file mode 100644
index 000000000..a917f829d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KFE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KGS.bmp b/plugins/channelrx/demodadsb/airlinelogos/KGS.bmp
new file mode 100644
index 000000000..590fe15a3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KGS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KII.bmp b/plugins/channelrx/demodadsb/airlinelogos/KII.bmp
new file mode 100644
index 000000000..6cc852b61
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KII.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KIS.bmp b/plugins/channelrx/demodadsb/airlinelogos/KIS.bmp
new file mode 100644
index 000000000..b53287d90
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KIS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KLJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/KLJ.bmp
new file mode 100644
index 000000000..4b41ddac0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KLJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KLM.bmp b/plugins/channelrx/demodadsb/airlinelogos/KLM.bmp
index a1aca8fff..79e7c15de 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/KLM.bmp and b/plugins/channelrx/demodadsb/airlinelogos/KLM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KME.bmp b/plugins/channelrx/demodadsb/airlinelogos/KME.bmp
new file mode 100644
index 000000000..c7c2689a6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KME.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KMI.bmp b/plugins/channelrx/demodadsb/airlinelogos/KMI.bmp
new file mode 100644
index 000000000..27516eb36
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KMI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KMK.bmp b/plugins/channelrx/demodadsb/airlinelogos/KMK.bmp
new file mode 100644
index 000000000..6f88d0c43
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KMK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KNE.bmp b/plugins/channelrx/demodadsb/airlinelogos/KNE.bmp
index 6a5e9f870..ed8375e9c 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/KNE.bmp and b/plugins/channelrx/demodadsb/airlinelogos/KNE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KQA.bmp b/plugins/channelrx/demodadsb/airlinelogos/KQA.bmp
index b4f746443..a7041ed8d 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/KQA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/KQA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KRE.bmp b/plugins/channelrx/demodadsb/airlinelogos/KRE.bmp
index aaaddcbe4..dd9a17884 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/KRE.bmp and b/plugins/channelrx/demodadsb/airlinelogos/KRE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KSZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/KSZ.bmp
new file mode 100644
index 000000000..bac0a5665
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KSZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KTB.bmp b/plugins/channelrx/demodadsb/airlinelogos/KTB.bmp
new file mode 100644
index 000000000..809d674e0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KTB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KYE.bmp b/plugins/channelrx/demodadsb/airlinelogos/KYE.bmp
new file mode 100644
index 000000000..9418e5c83
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KYE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/KZU.bmp b/plugins/channelrx/demodadsb/airlinelogos/KZU.bmp
new file mode 100644
index 000000000..3767a6e8c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/KZU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LAE.bmp b/plugins/channelrx/demodadsb/airlinelogos/LAE.bmp
new file mode 100644
index 000000000..30e7ee000
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LAE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LAK.bmp b/plugins/channelrx/demodadsb/airlinelogos/LAK.bmp
new file mode 100644
index 000000000..1aa4181f1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LAK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LAM.bmp b/plugins/channelrx/demodadsb/airlinelogos/LAM.bmp
new file mode 100644
index 000000000..a36ff20cc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LAM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LAN.bmp b/plugins/channelrx/demodadsb/airlinelogos/LAN.bmp
index 44e8a61e0..2d119d3ea 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/LAN.bmp and b/plugins/channelrx/demodadsb/airlinelogos/LAN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LAO.bmp b/plugins/channelrx/demodadsb/airlinelogos/LAO.bmp
new file mode 100644
index 000000000..8fbe74660
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LAO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LAU.bmp b/plugins/channelrx/demodadsb/airlinelogos/LAU.bmp
new file mode 100644
index 000000000..86b5f47ca
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LAU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LBQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/LBQ.bmp
new file mode 100644
index 000000000..43e8ac9c0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LBQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LBT.bmp b/plugins/channelrx/demodadsb/airlinelogos/LBT.bmp
new file mode 100644
index 000000000..6407e36c1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LBT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LDC.bmp b/plugins/channelrx/demodadsb/airlinelogos/LDC.bmp
new file mode 100644
index 000000000..10f72eae8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LDC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LDX.bmp b/plugins/channelrx/demodadsb/airlinelogos/LDX.bmp
new file mode 100644
index 000000000..ac86a3099
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LDX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LEX.bmp b/plugins/channelrx/demodadsb/airlinelogos/LEX.bmp
new file mode 100644
index 000000000..6942abe80
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LEX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LGF.bmp b/plugins/channelrx/demodadsb/airlinelogos/LGF.bmp
new file mode 100644
index 000000000..c6b723a35
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LGF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LGT.bmp b/plugins/channelrx/demodadsb/airlinelogos/LGT.bmp
new file mode 100644
index 000000000..0bf63597e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LGT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LHA.bmp b/plugins/channelrx/demodadsb/airlinelogos/LHA.bmp
new file mode 100644
index 000000000..d9b6d32b7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LHA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LIP.bmp b/plugins/channelrx/demodadsb/airlinelogos/LIP.bmp
new file mode 100644
index 000000000..b2c770a04
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LIP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LJC.bmp b/plugins/channelrx/demodadsb/airlinelogos/LJC.bmp
new file mode 100644
index 000000000..7618e15bf
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LJC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LJY.bmp b/plugins/channelrx/demodadsb/airlinelogos/LJY.bmp
new file mode 100644
index 000000000..939e0454c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LJY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LKF.bmp b/plugins/channelrx/demodadsb/airlinelogos/LKF.bmp
new file mode 100644
index 000000000..2f12dd304
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LKF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LKN.bmp b/plugins/channelrx/demodadsb/airlinelogos/LKN.bmp
new file mode 100644
index 000000000..ccce2c7d7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LKN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LLK.bmp b/plugins/channelrx/demodadsb/airlinelogos/LLK.bmp
new file mode 100644
index 000000000..a3b09c204
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LLK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LLL.bmp b/plugins/channelrx/demodadsb/airlinelogos/LLL.bmp
new file mode 100644
index 000000000..5fb54a145
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LLL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LLM.bmp b/plugins/channelrx/demodadsb/airlinelogos/LLM.bmp
new file mode 100644
index 000000000..9672c4afc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LLM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LMD.bmp b/plugins/channelrx/demodadsb/airlinelogos/LMD.bmp
new file mode 100644
index 000000000..9b0b3ea61
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LMD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LOG.bmp b/plugins/channelrx/demodadsb/airlinelogos/LOG.bmp
index a1538b09c..4f94cc9ee 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/LOG.bmp and b/plugins/channelrx/demodadsb/airlinelogos/LOG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LRS.bmp b/plugins/channelrx/demodadsb/airlinelogos/LRS.bmp
new file mode 100644
index 000000000..3f430e4a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LRS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LSO.bmp b/plugins/channelrx/demodadsb/airlinelogos/LSO.bmp
new file mode 100644
index 000000000..e6a4dbd78
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LSO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LTC.bmp b/plugins/channelrx/demodadsb/airlinelogos/LTC.bmp
new file mode 100644
index 000000000..0721ef7c0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LTC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LTR.bmp b/plugins/channelrx/demodadsb/airlinelogos/LTR.bmp
new file mode 100644
index 000000000..64786be3d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LTR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LVT.bmp b/plugins/channelrx/demodadsb/airlinelogos/LVT.bmp
new file mode 100644
index 000000000..d3e118b7f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LVT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LWA.bmp b/plugins/channelrx/demodadsb/airlinelogos/LWA.bmp
new file mode 100644
index 000000000..b1c8548f5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LWA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LXG.bmp b/plugins/channelrx/demodadsb/airlinelogos/LXG.bmp
new file mode 100644
index 000000000..b852cef04
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LXG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/LXJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/LXJ.bmp
new file mode 100644
index 000000000..0086a5fc7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/LXJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MAC.bmp b/plugins/channelrx/demodadsb/airlinelogos/MAC.bmp
index 2b96be6d5..50cd921c8 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/MAC.bmp and b/plugins/channelrx/demodadsb/airlinelogos/MAC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MAI.bmp b/plugins/channelrx/demodadsb/airlinelogos/MAI.bmp
new file mode 100644
index 000000000..c30f98812
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MAI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MAV.bmp b/plugins/channelrx/demodadsb/airlinelogos/MAV.bmp
new file mode 100644
index 000000000..eb605ba8f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MAV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MAX.bmp b/plugins/channelrx/demodadsb/airlinelogos/MAX.bmp
new file mode 100644
index 000000000..c1c0c72e9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MAX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MAY.bmp b/plugins/channelrx/demodadsb/airlinelogos/MAY.bmp
new file mode 100644
index 000000000..f25048c29
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MAY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MBA.bmp b/plugins/channelrx/demodadsb/airlinelogos/MBA.bmp
new file mode 100644
index 000000000..b951a1bfc
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MBA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MCM.bmp b/plugins/channelrx/demodadsb/airlinelogos/MCM.bmp
new file mode 100644
index 000000000..db50c5a81
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MCM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MDA.bmp b/plugins/channelrx/demodadsb/airlinelogos/MDA.bmp
new file mode 100644
index 000000000..09b76dee1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MDA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MFG.bmp b/plugins/channelrx/demodadsb/airlinelogos/MFG.bmp
new file mode 100644
index 000000000..6c163c9fa
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MFG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MGE.bmp b/plugins/channelrx/demodadsb/airlinelogos/MGE.bmp
new file mode 100644
index 000000000..cff86987e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MGE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MGL.bmp b/plugins/channelrx/demodadsb/airlinelogos/MGL.bmp
new file mode 100644
index 000000000..e148a5333
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MGL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MGP.bmp b/plugins/channelrx/demodadsb/airlinelogos/MGP.bmp
new file mode 100644
index 000000000..a133e3a7e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MGP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MHO.bmp b/plugins/channelrx/demodadsb/airlinelogos/MHO.bmp
new file mode 100644
index 000000000..283d8af5f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MHO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MHV.bmp b/plugins/channelrx/demodadsb/airlinelogos/MHV.bmp
new file mode 100644
index 000000000..5da91b2f0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MHV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MKG.bmp b/plugins/channelrx/demodadsb/airlinelogos/MKG.bmp
index 6fcd1fd9b..6e0e1d8ac 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/MKG.bmp and b/plugins/channelrx/demodadsb/airlinelogos/MKG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MKR.bmp b/plugins/channelrx/demodadsb/airlinelogos/MKR.bmp
new file mode 100644
index 000000000..3339885b7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MKR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MLN.bmp b/plugins/channelrx/demodadsb/airlinelogos/MLN.bmp
new file mode 100644
index 000000000..e83c4146d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MLN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MLT.bmp b/plugins/channelrx/demodadsb/airlinelogos/MLT.bmp
index 9012df2c3..e2bc2691b 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/MLT.bmp and b/plugins/channelrx/demodadsb/airlinelogos/MLT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MML.bmp b/plugins/channelrx/demodadsb/airlinelogos/MML.bmp
new file mode 100644
index 000000000..4bb61a3e5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MML.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MMN.bmp b/plugins/channelrx/demodadsb/airlinelogos/MMN.bmp
new file mode 100644
index 000000000..c16ff4f3a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MMN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MNG.bmp b/plugins/channelrx/demodadsb/airlinelogos/MNG.bmp
new file mode 100644
index 000000000..43b56c7ed
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MNG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MNU.bmp b/plugins/channelrx/demodadsb/airlinelogos/MNU.bmp
new file mode 100644
index 000000000..08ccdad9d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MNU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MPK.bmp b/plugins/channelrx/demodadsb/airlinelogos/MPK.bmp
new file mode 100644
index 000000000..3a5c05b85
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MPK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MSA.bmp b/plugins/channelrx/demodadsb/airlinelogos/MSA.bmp
new file mode 100644
index 000000000..e234c2659
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MSA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MSI.bmp b/plugins/channelrx/demodadsb/airlinelogos/MSI.bmp
new file mode 100644
index 000000000..79f3de3c3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MSI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MSJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/MSJ.bmp
new file mode 100644
index 000000000..c71d7fa8d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MSJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MTL.bmp b/plugins/channelrx/demodadsb/airlinelogos/MTL.bmp
new file mode 100644
index 000000000..4798283a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MTL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MTN.bmp b/plugins/channelrx/demodadsb/airlinelogos/MTN.bmp
new file mode 100644
index 000000000..6ba366cb3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MTN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MUL.bmp b/plugins/channelrx/demodadsb/airlinelogos/MUL.bmp
new file mode 100644
index 000000000..463b637be
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MUL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MUT.bmp b/plugins/channelrx/demodadsb/airlinelogos/MUT.bmp
new file mode 100644
index 000000000..f9480248f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MUT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MWI.bmp b/plugins/channelrx/demodadsb/airlinelogos/MWI.bmp
new file mode 100644
index 000000000..5ca87c191
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MWI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MWM.bmp b/plugins/channelrx/demodadsb/airlinelogos/MWM.bmp
new file mode 100644
index 000000000..b2eff53c5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MWM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MXD.bmp b/plugins/channelrx/demodadsb/airlinelogos/MXD.bmp
new file mode 100644
index 000000000..868e55d97
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MXD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MYA.bmp b/plugins/channelrx/demodadsb/airlinelogos/MYA.bmp
new file mode 100644
index 000000000..a319090d1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MYA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MYP.bmp b/plugins/channelrx/demodadsb/airlinelogos/MYP.bmp
index 09b8981f4..7f7049af0 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/MYP.bmp and b/plugins/channelrx/demodadsb/airlinelogos/MYP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/MYW.bmp b/plugins/channelrx/demodadsb/airlinelogos/MYW.bmp
new file mode 100644
index 000000000..94c19381a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/MYW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NAA.bmp b/plugins/channelrx/demodadsb/airlinelogos/NAA.bmp
new file mode 100644
index 000000000..f68a55e81
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NAA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NAC.bmp b/plugins/channelrx/demodadsb/airlinelogos/NAC.bmp
index 6b46b0779..2b8ba779a 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/NAC.bmp and b/plugins/channelrx/demodadsb/airlinelogos/NAC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NCR.bmp b/plugins/channelrx/demodadsb/airlinelogos/NCR.bmp
new file mode 100644
index 000000000..67c1fb936
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NCR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NFA.bmp b/plugins/channelrx/demodadsb/airlinelogos/NFA.bmp
new file mode 100644
index 000000000..b186ab65b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NFA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NHX.bmp b/plugins/channelrx/demodadsb/airlinelogos/NHX.bmp
new file mode 100644
index 000000000..969c32f35
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NHX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NIG.bmp b/plugins/channelrx/demodadsb/airlinelogos/NIG.bmp
new file mode 100644
index 000000000..25ebfbd74
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NIG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NIH.bmp b/plugins/channelrx/demodadsb/airlinelogos/NIH.bmp
new file mode 100644
index 000000000..80b0ce063
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NIH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NIN.bmp b/plugins/channelrx/demodadsb/airlinelogos/NIN.bmp
new file mode 100644
index 000000000..203d5970d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NIN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NIS.bmp b/plugins/channelrx/demodadsb/airlinelogos/NIS.bmp
new file mode 100644
index 000000000..475eb09e7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NIS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NJE.bmp b/plugins/channelrx/demodadsb/airlinelogos/NJE.bmp
new file mode 100644
index 000000000..0667656c0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NJE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NKT.bmp b/plugins/channelrx/demodadsb/airlinelogos/NKT.bmp
new file mode 100644
index 000000000..f6c54a9fe
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NKT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NLA.bmp b/plugins/channelrx/demodadsb/airlinelogos/NLA.bmp
new file mode 100644
index 000000000..48903fabe
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NLA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NMG.bmp b/plugins/channelrx/demodadsb/airlinelogos/NMG.bmp
new file mode 100644
index 000000000..a7a9648d3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NMG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NOK.bmp b/plugins/channelrx/demodadsb/airlinelogos/NOK.bmp
index 15504872b..494fad4e6 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/NOK.bmp and b/plugins/channelrx/demodadsb/airlinelogos/NOK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NPT.bmp b/plugins/channelrx/demodadsb/airlinelogos/NPT.bmp
index c8fbb5483..57180cd56 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/NPT.bmp and b/plugins/channelrx/demodadsb/airlinelogos/NPT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NRS.bmp b/plugins/channelrx/demodadsb/airlinelogos/NRS.bmp
new file mode 100644
index 000000000..0738763b3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NRS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NSJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/NSJ.bmp
new file mode 100644
index 000000000..01ab09542
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NSJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NSW.bmp b/plugins/channelrx/demodadsb/airlinelogos/NSW.bmp
new file mode 100644
index 000000000..76cabb2ce
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NSW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NTB.bmp b/plugins/channelrx/demodadsb/airlinelogos/NTB.bmp
new file mode 100644
index 000000000..587e6cac4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NTB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NTF.bmp b/plugins/channelrx/demodadsb/airlinelogos/NTF.bmp
new file mode 100644
index 000000000..e6a144a80
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NTF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NUM.bmp b/plugins/channelrx/demodadsb/airlinelogos/NUM.bmp
new file mode 100644
index 000000000..e70ba0800
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NUM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NWG.bmp b/plugins/channelrx/demodadsb/airlinelogos/NWG.bmp
new file mode 100644
index 000000000..6464a2496
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NWG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NWL.bmp b/plugins/channelrx/demodadsb/airlinelogos/NWL.bmp
new file mode 100644
index 000000000..1e61b35f3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NWL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NWS.bmp b/plugins/channelrx/demodadsb/airlinelogos/NWS.bmp
index 19696685d..ae85e91ff 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/NWS.bmp and b/plugins/channelrx/demodadsb/airlinelogos/NWS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NYS.bmp b/plugins/channelrx/demodadsb/airlinelogos/NYS.bmp
new file mode 100644
index 000000000..643a15b5d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NYS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NYT.bmp b/plugins/channelrx/demodadsb/airlinelogos/NYT.bmp
new file mode 100644
index 000000000..38fc7b3f6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NYT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/NYX.bmp b/plugins/channelrx/demodadsb/airlinelogos/NYX.bmp
new file mode 100644
index 000000000..89410056d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/NYX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OAW.bmp b/plugins/channelrx/demodadsb/airlinelogos/OAW.bmp
new file mode 100644
index 000000000..89c254603
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OAW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OCL.bmp b/plugins/channelrx/demodadsb/airlinelogos/OCL.bmp
new file mode 100644
index 000000000..787238de0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OCL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OES.bmp b/plugins/channelrx/demodadsb/airlinelogos/OES.bmp
new file mode 100644
index 000000000..44d0aca0a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OES.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OIX.bmp b/plugins/channelrx/demodadsb/airlinelogos/OIX.bmp
new file mode 100644
index 000000000..e2029442f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OIX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OKC.bmp b/plugins/channelrx/demodadsb/airlinelogos/OKC.bmp
new file mode 100644
index 000000000..84f7a7282
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OKC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OLS.bmp b/plugins/channelrx/demodadsb/airlinelogos/OLS.bmp
new file mode 100644
index 000000000..87f8b36c9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OLS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OMS.bmp b/plugins/channelrx/demodadsb/airlinelogos/OMS.bmp
new file mode 100644
index 000000000..54ceb701d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OMS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OMT.bmp b/plugins/channelrx/demodadsb/airlinelogos/OMT.bmp
new file mode 100644
index 000000000..6aa0a4b6f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OMT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ORN.bmp b/plugins/channelrx/demodadsb/airlinelogos/ORN.bmp
new file mode 100644
index 000000000..e52d56146
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ORN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OTF.bmp b/plugins/channelrx/demodadsb/airlinelogos/OTF.bmp
new file mode 100644
index 000000000..949d1a30c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OTF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OWT.bmp b/plugins/channelrx/demodadsb/airlinelogos/OWT.bmp
new file mode 100644
index 000000000..9020a0b34
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OWT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/OXM.bmp b/plugins/channelrx/demodadsb/airlinelogos/OXM.bmp
new file mode 100644
index 000000000..e3ed1477b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/OXM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PAC.bmp b/plugins/channelrx/demodadsb/airlinelogos/PAC.bmp
new file mode 100644
index 000000000..6dbc5e660
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PAC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PACIFIC.bmp b/plugins/channelrx/demodadsb/airlinelogos/PACIFIC.bmp
new file mode 100644
index 000000000..decb8c3f9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PACIFIC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PAJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/PAJ.bmp
new file mode 100644
index 000000000..50c6f651a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PAJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PAO.bmp b/plugins/channelrx/demodadsb/airlinelogos/PAO.bmp
new file mode 100644
index 000000000..dda848ab1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PAO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PAPILLON.bmp b/plugins/channelrx/demodadsb/airlinelogos/PAPILLON.bmp
new file mode 100644
index 000000000..a8d7d08f1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PAPILLON.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PAV.bmp b/plugins/channelrx/demodadsb/airlinelogos/PAV.bmp
new file mode 100644
index 000000000..e5193b4c4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PAV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PBD.bmp b/plugins/channelrx/demodadsb/airlinelogos/PBD.bmp
new file mode 100644
index 000000000..930d5b852
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PBD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PCO.bmp b/plugins/channelrx/demodadsb/airlinelogos/PCO.bmp
new file mode 100644
index 000000000..34c75bfb8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PCO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PHU.bmp b/plugins/channelrx/demodadsb/airlinelogos/PHU.bmp
new file mode 100644
index 000000000..83f482d34
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PHU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/PIA.bmp
index 700c14da7..78da48392 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/PIA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/PIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PICa.bmp b/plugins/channelrx/demodadsb/airlinelogos/PICa.bmp
new file mode 100644
index 000000000..904711ab3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PICa.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PICb.bmp b/plugins/channelrx/demodadsb/airlinelogos/PICb.bmp
new file mode 100644
index 000000000..b70864563
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PICb.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PJC.bmp b/plugins/channelrx/demodadsb/airlinelogos/PJC.bmp
new file mode 100644
index 000000000..9a44da3ec
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PJC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PJS.bmp b/plugins/channelrx/demodadsb/airlinelogos/PJS.bmp
new file mode 100644
index 000000000..31ec3ee5a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PJS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PLANET9.bmp b/plugins/channelrx/demodadsb/airlinelogos/PLANET9.bmp
new file mode 100644
index 000000000..28ca36d03
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PLANET9.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PLM.bmp b/plugins/channelrx/demodadsb/airlinelogos/PLM.bmp
index 0b025e112..d208bcb67 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/PLM.bmp and b/plugins/channelrx/demodadsb/airlinelogos/PLM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PNC.bmp b/plugins/channelrx/demodadsb/airlinelogos/PNC.bmp
new file mode 100644
index 000000000..3ab4e31e8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PNC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PNX.bmp b/plugins/channelrx/demodadsb/airlinelogos/PNX.bmp
new file mode 100644
index 000000000..ea0d61767
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PNX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PTH.bmp b/plugins/channelrx/demodadsb/airlinelogos/PTH.bmp
new file mode 100644
index 000000000..55a3b554f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PTH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PUA.bmp b/plugins/channelrx/demodadsb/airlinelogos/PUA.bmp
new file mode 100644
index 000000000..b1d7da71e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PUA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PUE.bmp b/plugins/channelrx/demodadsb/airlinelogos/PUE.bmp
new file mode 100644
index 000000000..c67eb2a68
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PUE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PUN.bmp b/plugins/channelrx/demodadsb/airlinelogos/PUN.bmp
new file mode 100644
index 000000000..68ea030ca
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PUN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PVD.bmp b/plugins/channelrx/demodadsb/airlinelogos/PVD.bmp
new file mode 100644
index 000000000..af26dc89d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PVD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PVO.bmp b/plugins/channelrx/demodadsb/airlinelogos/PVO.bmp
new file mode 100644
index 000000000..65674fc82
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PVO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PVV.bmp b/plugins/channelrx/demodadsb/airlinelogos/PVV.bmp
new file mode 100644
index 000000000..68fb2595a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PVV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/PXG.bmp b/plugins/channelrx/demodadsb/airlinelogos/PXG.bmp
new file mode 100644
index 000000000..fba3ecc9a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/PXG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/QAZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/QAZ.bmp
new file mode 100644
index 000000000..7083b1700
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/QAZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/QBA.bmp b/plugins/channelrx/demodadsb/airlinelogos/QBA.bmp
new file mode 100644
index 000000000..8a3eb3f1b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/QBA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/QSM.bmp b/plugins/channelrx/demodadsb/airlinelogos/QSM.bmp
new file mode 100644
index 000000000..7253ce0e3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/QSM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/QXE.bmp b/plugins/channelrx/demodadsb/airlinelogos/QXE.bmp
new file mode 100644
index 000000000..8f8dcce6d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/QXE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RAC.bmp b/plugins/channelrx/demodadsb/airlinelogos/RAC.bmp
new file mode 100644
index 000000000..2aa50f933
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RAC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RBB.bmp b/plugins/channelrx/demodadsb/airlinelogos/RBB.bmp
new file mode 100644
index 000000000..a9bca9fd1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RBB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RDS.bmp b/plugins/channelrx/demodadsb/airlinelogos/RDS.bmp
new file mode 100644
index 000000000..34aa920ab
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RDS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RKS.bmp b/plugins/channelrx/demodadsb/airlinelogos/RKS.bmp
new file mode 100644
index 000000000..a7875598c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RKS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RLA.bmp b/plugins/channelrx/demodadsb/airlinelogos/RLA.bmp
index 87a496696..6092100ef 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/RLA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/RLA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RLY.bmp b/plugins/channelrx/demodadsb/airlinelogos/RLY.bmp
new file mode 100644
index 000000000..9bad04bac
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RLY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RMY.bmp b/plugins/channelrx/demodadsb/airlinelogos/RMY.bmp
new file mode 100644
index 000000000..53331a009
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RMY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RNA.bmp b/plugins/channelrx/demodadsb/airlinelogos/RNA.bmp
new file mode 100644
index 000000000..234cb1142
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RNA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ROJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/ROJ.bmp
new file mode 100644
index 000000000..96a963ad6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ROJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RPA.bmp b/plugins/channelrx/demodadsb/airlinelogos/RPA.bmp
new file mode 100644
index 000000000..e0fd0ee03
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RPA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RPB.bmp b/plugins/channelrx/demodadsb/airlinelogos/RPB.bmp
index 796b691a8..9416c8fd2 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/RPB.bmp and b/plugins/channelrx/demodadsb/airlinelogos/RPB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RPM.bmp b/plugins/channelrx/demodadsb/airlinelogos/RPM.bmp
new file mode 100644
index 000000000..455fbcb5d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RPM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RSI.bmp b/plugins/channelrx/demodadsb/airlinelogos/RSI.bmp
new file mode 100644
index 000000000..3773d5ac6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RSI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RSY.bmp b/plugins/channelrx/demodadsb/airlinelogos/RSY.bmp
index 827a2dcd9..b2bcf9a53 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/RSY.bmp and b/plugins/channelrx/demodadsb/airlinelogos/RSY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RTL.bmp b/plugins/channelrx/demodadsb/airlinelogos/RTL.bmp
new file mode 100644
index 000000000..b1cfc072c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RTL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RUC.bmp b/plugins/channelrx/demodadsb/airlinelogos/RUC.bmp
index a8d1dce73..1ef183b58 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/RUC.bmp and b/plugins/channelrx/demodadsb/airlinelogos/RUC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RUK.bmp b/plugins/channelrx/demodadsb/airlinelogos/RUK.bmp
new file mode 100644
index 000000000..af458dfb0
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RUK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RUN.bmp b/plugins/channelrx/demodadsb/airlinelogos/RUN.bmp
new file mode 100644
index 000000000..d8f341932
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RUN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RVP.bmp b/plugins/channelrx/demodadsb/airlinelogos/RVP.bmp
new file mode 100644
index 000000000..ebb38272b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RVP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RWD.bmp b/plugins/channelrx/demodadsb/airlinelogos/RWD.bmp
new file mode 100644
index 000000000..94cdbc670
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RWD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/RYL.bmp b/plugins/channelrx/demodadsb/airlinelogos/RYL.bmp
new file mode 100644
index 000000000..5719aa48d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/RYL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SAA.bmp b/plugins/channelrx/demodadsb/airlinelogos/SAA.bmp
new file mode 100644
index 000000000..70b54d8e6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SAA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SAR.bmp b/plugins/channelrx/demodadsb/airlinelogos/SAR.bmp
new file mode 100644
index 000000000..d66425920
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SAR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SAS.bmp b/plugins/channelrx/demodadsb/airlinelogos/SAS.bmp
index 029648f2d..353967312 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SAS.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SAS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SAW.bmp b/plugins/channelrx/demodadsb/airlinelogos/SAW.bmp
new file mode 100644
index 000000000..2ae9a8743
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SAW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SAY.bmp b/plugins/channelrx/demodadsb/airlinelogos/SAY.bmp
new file mode 100644
index 000000000..b23b0a15e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SAY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SBB.bmp b/plugins/channelrx/demodadsb/airlinelogos/SBB.bmp
new file mode 100644
index 000000000..e52740e9e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SBB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SBI.bmp b/plugins/channelrx/demodadsb/airlinelogos/SBI.bmp
new file mode 100644
index 000000000..c421badb1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SBI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SBL.bmp b/plugins/channelrx/demodadsb/airlinelogos/SBL.bmp
new file mode 100644
index 000000000..9887c58a2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SBL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SBS.bmp b/plugins/channelrx/demodadsb/airlinelogos/SBS.bmp
new file mode 100644
index 000000000..bda095c9c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SBS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SBU.bmp b/plugins/channelrx/demodadsb/airlinelogos/SBU.bmp
new file mode 100644
index 000000000..fb4b400c8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SBU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SCN.bmp b/plugins/channelrx/demodadsb/airlinelogos/SCN.bmp
new file mode 100644
index 000000000..f8af1f9e6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SCN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SCX.bmp b/plugins/channelrx/demodadsb/airlinelogos/SCX.bmp
index a722883a9..f179ab11c 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SCX.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SCX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SDA.bmp b/plugins/channelrx/demodadsb/airlinelogos/SDA.bmp
new file mode 100644
index 000000000..19cacb04f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SDA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SDG.bmp b/plugins/channelrx/demodadsb/airlinelogos/SDG.bmp
new file mode 100644
index 000000000..f367cc987
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SDG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SDM.bmp b/plugins/channelrx/demodadsb/airlinelogos/SDM.bmp
index e3b861b56..2555ce9b1 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SDM.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SDM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SDU.bmp b/plugins/channelrx/demodadsb/airlinelogos/SDU.bmp
new file mode 100644
index 000000000..bb0318ff8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SDU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SEH.bmp b/plugins/channelrx/demodadsb/airlinelogos/SEH.bmp
new file mode 100644
index 000000000..802e6acf3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SEH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SEJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SEJ.bmp
index 050a24874..39f306c61 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SEJ.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SEJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SEP.bmp b/plugins/channelrx/demodadsb/airlinelogos/SEP.bmp
new file mode 100644
index 000000000..862bc5da2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SEP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SET.bmp b/plugins/channelrx/demodadsb/airlinelogos/SET.bmp
new file mode 100644
index 000000000..087e6c0a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SET.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SEY.bmp b/plugins/channelrx/demodadsb/airlinelogos/SEY.bmp
index 9c48b5793..b47cce2db 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SEY.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SEY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SFJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SFJ.bmp
new file mode 100644
index 000000000..f1adc2659
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SFJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SFR.bmp b/plugins/channelrx/demodadsb/airlinelogos/SFR.bmp
new file mode 100644
index 000000000..e3ec818f6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SFR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SFS.bmp b/plugins/channelrx/demodadsb/airlinelogos/SFS.bmp
new file mode 100644
index 000000000..f55420cd6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SFS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SGB.bmp b/plugins/channelrx/demodadsb/airlinelogos/SGB.bmp
new file mode 100644
index 000000000..451ae35cf
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SGB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SGQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SGQ.bmp
new file mode 100644
index 000000000..30b84d42e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SGQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SHH.bmp b/plugins/channelrx/demodadsb/airlinelogos/SHH.bmp
new file mode 100644
index 000000000..5e3787d1a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SHH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SHI.bmp b/plugins/channelrx/demodadsb/airlinelogos/SHI.bmp
new file mode 100644
index 000000000..e4b478a33
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SHI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SHU.bmp b/plugins/channelrx/demodadsb/airlinelogos/SHU.bmp
index feb41a4ef..0100d66ca 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SHU.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SHU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/SIA.bmp
index d5d586278..8597c8b1c 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SIA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SIF.bmp b/plugins/channelrx/demodadsb/airlinelogos/SIF.bmp
index c4155b05c..31fbac168 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SIF.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SIF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SIL.bmp b/plugins/channelrx/demodadsb/airlinelogos/SIL.bmp
new file mode 100644
index 000000000..73a286b52
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SIL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SIS.bmp b/plugins/channelrx/demodadsb/airlinelogos/SIS.bmp
new file mode 100644
index 000000000..4e08c75df
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SIS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SIY.bmp b/plugins/channelrx/demodadsb/airlinelogos/SIY.bmp
new file mode 100644
index 000000000..a11d21857
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SIY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SJJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SJJ.bmp
new file mode 100644
index 000000000..737d1692f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SJJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SJO.bmp b/plugins/channelrx/demodadsb/airlinelogos/SJO.bmp
index 98841c2e7..c811e0c86 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SJO.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SJO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SJX.bmp b/plugins/channelrx/demodadsb/airlinelogos/SJX.bmp
new file mode 100644
index 000000000..07f221aaa
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SJX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SJY.bmp b/plugins/channelrx/demodadsb/airlinelogos/SJY.bmp
new file mode 100644
index 000000000..799bea34b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SJY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKIPPERS.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKIPPERS.bmp
new file mode 100644
index 000000000..a736196d7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SKIPPERS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKK.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKK.bmp
index d8d5e43a7..5f3c136ff 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SKK.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SKK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKP.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKP.bmp
index 65b87a48d..9e2b37c91 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SKP.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SKP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKU.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKU.bmp
index c5afca54e..9a058f7e2 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SKU.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SKU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKW.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKW.bmp
new file mode 100644
index 000000000..1e76f2bce
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SKW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKX.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKX.bmp
new file mode 100644
index 000000000..9a058f7e2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SKX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKY.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKY.bmp
new file mode 100644
index 000000000..b78cd8ef9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SKY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKYDIVESTRATH.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKYDIVESTRATH.bmp
new file mode 100644
index 000000000..32840182a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SKYDIVESTRATH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKYDIVESTRATHa.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKYDIVESTRATHa.bmp
new file mode 100644
index 000000000..96be819ba
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SKYDIVESTRATHa.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SLK.bmp b/plugins/channelrx/demodadsb/airlinelogos/SLK.bmp
index c15cbaf46..4ed624910 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SLK.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SLK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SLQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SLQ.bmp
new file mode 100644
index 000000000..6409bffce
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SLQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SNA.bmp b/plugins/channelrx/demodadsb/airlinelogos/SNA.bmp
new file mode 100644
index 000000000..6a7b33779
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SNA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SNG.bmp b/plugins/channelrx/demodadsb/airlinelogos/SNG.bmp
new file mode 100644
index 000000000..7cf1c417a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SNG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SNJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SNJ.bmp
new file mode 100644
index 000000000..1e9903d36
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SNJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SOL.bmp b/plugins/channelrx/demodadsb/airlinelogos/SOL.bmp
new file mode 100644
index 000000000..5077c56c1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SOL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SONOCO.bmp b/plugins/channelrx/demodadsb/airlinelogos/SONOCO.bmp
new file mode 100644
index 000000000..028c2d49e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SONOCO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SOO.bmp b/plugins/channelrx/demodadsb/airlinelogos/SOO.bmp
new file mode 100644
index 000000000..87045c4cd
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SOO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SOW.bmp b/plugins/channelrx/demodadsb/airlinelogos/SOW.bmp
new file mode 100644
index 000000000..b18a427b5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SOW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SPD.bmp b/plugins/channelrx/demodadsb/airlinelogos/SPD.bmp
new file mode 100644
index 000000000..8c208126d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SPD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SQH.bmp b/plugins/channelrx/demodadsb/airlinelogos/SQH.bmp
new file mode 100644
index 000000000..cca61dc3b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SQH.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SQP.bmp b/plugins/channelrx/demodadsb/airlinelogos/SQP.bmp
new file mode 100644
index 000000000..69f5f5ebe
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SQP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SRC.bmp b/plugins/channelrx/demodadsb/airlinelogos/SRC.bmp
new file mode 100644
index 000000000..346277e18
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SRC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SRN.bmp b/plugins/channelrx/demodadsb/airlinelogos/SRN.bmp
new file mode 100644
index 000000000..d66425920
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SRN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SRQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SRQ.bmp
new file mode 100644
index 000000000..f572cf910
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SRQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SSF.bmp b/plugins/channelrx/demodadsb/airlinelogos/SSF.bmp
new file mode 100644
index 000000000..0cec3203e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SSF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SSX.bmp b/plugins/channelrx/demodadsb/airlinelogos/SSX.bmp
new file mode 100644
index 000000000..9e75ccb62
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SSX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/STP.bmp b/plugins/channelrx/demodadsb/airlinelogos/STP.bmp
new file mode 100644
index 000000000..9c42de1ba
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/STP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/STRAT.bmp b/plugins/channelrx/demodadsb/airlinelogos/STRAT.bmp
new file mode 100644
index 000000000..affc87f4e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/STRAT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SUD.bmp b/plugins/channelrx/demodadsb/airlinelogos/SUD.bmp
new file mode 100644
index 000000000..908236478
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SUD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SVA.bmp b/plugins/channelrx/demodadsb/airlinelogos/SVA.bmp
index 9fc3aa6c7..f497e9338 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SVA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SVA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SVW.bmp b/plugins/channelrx/demodadsb/airlinelogos/SVW.bmp
new file mode 100644
index 000000000..b2720b40f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SVW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SWA.bmp b/plugins/channelrx/demodadsb/airlinelogos/SWA.bmp
index 7efadee08..badb7c2ed 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SWA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SWA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SWM.bmp b/plugins/channelrx/demodadsb/airlinelogos/SWM.bmp
index b4aa65d40..d8b31245c 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/SWM.bmp and b/plugins/channelrx/demodadsb/airlinelogos/SWM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SWQ.bmp b/plugins/channelrx/demodadsb/airlinelogos/SWQ.bmp
new file mode 100644
index 000000000..76213e542
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SWQ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SXN.bmp b/plugins/channelrx/demodadsb/airlinelogos/SXN.bmp
new file mode 100644
index 000000000..93c692875
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SXN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SYG.bmp b/plugins/channelrx/demodadsb/airlinelogos/SYG.bmp
new file mode 100644
index 000000000..9053c7cd8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SYG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/SZN.bmp b/plugins/channelrx/demodadsb/airlinelogos/SZN.bmp
new file mode 100644
index 000000000..8271b334c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/SZN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TAG.bmp b/plugins/channelrx/demodadsb/airlinelogos/TAG.bmp
new file mode 100644
index 000000000..37a1fcc49
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TAG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TAN.bmp b/plugins/channelrx/demodadsb/airlinelogos/TAN.bmp
new file mode 100644
index 000000000..2f7bceac6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TAN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TAPexp.bmp b/plugins/channelrx/demodadsb/airlinelogos/TAPexp.bmp
new file mode 100644
index 000000000..34cb072a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TAPexp.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TBA.bmp b/plugins/channelrx/demodadsb/airlinelogos/TBA.bmp
index b98f9ff95..60deb6919 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TBA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TBA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TBM.bmp b/plugins/channelrx/demodadsb/airlinelogos/TBM.bmp
new file mode 100644
index 000000000..9c492f962
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TBM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TBZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/TBZ.bmp
index b1003371a..9106aa274 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TBZ.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TBZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TCB.bmp b/plugins/channelrx/demodadsb/airlinelogos/TCB.bmp
new file mode 100644
index 000000000..d19a5909e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TCB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TCV.bmp b/plugins/channelrx/demodadsb/airlinelogos/TCV.bmp
index ab36da733..ed26c836e 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TCV.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TCV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TDR.bmp b/plugins/channelrx/demodadsb/airlinelogos/TDR.bmp
index df6027bd5..de2b38d24 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TDR.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TDR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TEK.bmp b/plugins/channelrx/demodadsb/airlinelogos/TEK.bmp
new file mode 100644
index 000000000..9637012e2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TEK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TEU.bmp b/plugins/channelrx/demodadsb/airlinelogos/TEU.bmp
new file mode 100644
index 000000000..37a1fcc49
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TEU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TFF.bmp b/plugins/channelrx/demodadsb/airlinelogos/TFF.bmp
new file mode 100644
index 000000000..a3b6c7b95
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TFF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TGG.bmp b/plugins/channelrx/demodadsb/airlinelogos/TGG.bmp
new file mode 100644
index 000000000..6f6b25e2e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TGG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TGN.bmp b/plugins/channelrx/demodadsb/airlinelogos/TGN.bmp
new file mode 100644
index 000000000..052742400
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TGN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/THD.bmp b/plugins/channelrx/demodadsb/airlinelogos/THD.bmp
new file mode 100644
index 000000000..918cb1d3c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/THD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/THY.bmp b/plugins/channelrx/demodadsb/airlinelogos/THY.bmp
index 6ab1ad270..e5bd3c0c7 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/THY.bmp and b/plugins/channelrx/demodadsb/airlinelogos/THY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TIS.bmp b/plugins/channelrx/demodadsb/airlinelogos/TIS.bmp
new file mode 100644
index 000000000..dbe82abaa
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TIS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TIV.bmp b/plugins/channelrx/demodadsb/airlinelogos/TIV.bmp
new file mode 100644
index 000000000..de28dc2a6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TIV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TJB.bmp b/plugins/channelrx/demodadsb/airlinelogos/TJB.bmp
new file mode 100644
index 000000000..c2cfb7a63
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TJB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TJJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/TJJ.bmp
new file mode 100644
index 000000000..7717ef10f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TJJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TJT.bmp b/plugins/channelrx/demodadsb/airlinelogos/TJT.bmp
new file mode 100644
index 000000000..89bf21ef4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TJT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TKK.bmp b/plugins/channelrx/demodadsb/airlinelogos/TKK.bmp
new file mode 100644
index 000000000..bd83694a1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TKK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TLM.bmp b/plugins/channelrx/demodadsb/airlinelogos/TLM.bmp
new file mode 100644
index 000000000..1ed5f2669
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TLM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TMG.bmp b/plugins/channelrx/demodadsb/airlinelogos/TMG.bmp
new file mode 100644
index 000000000..3d8da9d49
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TMG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TNU.bmp b/plugins/channelrx/demodadsb/airlinelogos/TNU.bmp
new file mode 100644
index 000000000..cd18f8425
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TNU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TNX.bmp b/plugins/channelrx/demodadsb/airlinelogos/TNX.bmp
new file mode 100644
index 000000000..151dcfb8d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TNX.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TOK.bmp b/plugins/channelrx/demodadsb/airlinelogos/TOK.bmp
new file mode 100644
index 000000000..ebb7e088f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TOK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TOR.bmp b/plugins/channelrx/demodadsb/airlinelogos/TOR.bmp
new file mode 100644
index 000000000..bc0b73bb2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TOR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TRA.bmp b/plugins/channelrx/demodadsb/airlinelogos/TRA.bmp
index c011b760f..903123553 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TRA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TRA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TRJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/TRJ.bmp
new file mode 100644
index 000000000..7628a5be6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TRJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TTE.bmp b/plugins/channelrx/demodadsb/airlinelogos/TTE.bmp
new file mode 100644
index 000000000..b14566681
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TTE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TTI.bmp b/plugins/channelrx/demodadsb/airlinelogos/TTI.bmp
new file mode 100644
index 000000000..b2a499e2f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TTI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TTW.bmp b/plugins/channelrx/demodadsb/airlinelogos/TTW.bmp
new file mode 100644
index 000000000..41b529d3a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TTW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TUI.bmp b/plugins/channelrx/demodadsb/airlinelogos/TUI.bmp
index 25f796a4b..162f4dd52 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TUI.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TUI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TUP.bmp b/plugins/channelrx/demodadsb/airlinelogos/TUP.bmp
new file mode 100644
index 000000000..f429fe1c5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TUP.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TUS.bmp b/plugins/channelrx/demodadsb/airlinelogos/TUS.bmp
index fc255eebe..121d82650 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TUS.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TUS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TVF.bmp b/plugins/channelrx/demodadsb/airlinelogos/TVF.bmp
index b130257e5..903123553 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/TVF.bmp and b/plugins/channelrx/demodadsb/airlinelogos/TVF.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TVJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/TVJ.bmp
new file mode 100644
index 000000000..67a385764
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TVJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TVR.bmp b/plugins/channelrx/demodadsb/airlinelogos/TVR.bmp
new file mode 100644
index 000000000..5dbdd0d8d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TVR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TVV.bmp b/plugins/channelrx/demodadsb/airlinelogos/TVV.bmp
new file mode 100644
index 000000000..b12ce6eda
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TVV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TWB.bmp b/plugins/channelrx/demodadsb/airlinelogos/TWB.bmp
new file mode 100644
index 000000000..3361cecf4
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TWB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TWY.bmp b/plugins/channelrx/demodadsb/airlinelogos/TWY.bmp
new file mode 100644
index 000000000..c783b9a71
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TWY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/TYA.bmp b/plugins/channelrx/demodadsb/airlinelogos/TYA.bmp
new file mode 100644
index 000000000..c37a101f2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/TYA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UBA.bmp b/plugins/channelrx/demodadsb/airlinelogos/UBA.bmp
new file mode 100644
index 000000000..da2d7dfd5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UBA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UBD.bmp b/plugins/channelrx/demodadsb/airlinelogos/UBD.bmp
index e5200826a..13a5221af 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/UBD.bmp and b/plugins/channelrx/demodadsb/airlinelogos/UBD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UBG.bmp b/plugins/channelrx/demodadsb/airlinelogos/UBG.bmp
new file mode 100644
index 000000000..6c82ad980
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UBG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UCA.bmp b/plugins/channelrx/demodadsb/airlinelogos/UCA.bmp
index a086e2af8..001ba7cbf 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/UCA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/UCA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UDN.bmp b/plugins/channelrx/demodadsb/airlinelogos/UDN.bmp
new file mode 100644
index 000000000..451c2bca2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UDN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UFC.bmp b/plugins/channelrx/demodadsb/airlinelogos/UFC.bmp
new file mode 100644
index 000000000..e3cbb4717
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UFC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UGD.bmp b/plugins/channelrx/demodadsb/airlinelogos/UGD.bmp
new file mode 100644
index 000000000..0a3e8674f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UGD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/UIA.bmp
new file mode 100644
index 000000000..2e25e4f77
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UJC.bmp b/plugins/channelrx/demodadsb/airlinelogos/UJC.bmp
new file mode 100644
index 000000000..e302d49b8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UJC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UKM.bmp b/plugins/channelrx/demodadsb/airlinelogos/UKM.bmp
new file mode 100644
index 000000000..72c9479f7
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UKM.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ULC.bmp b/plugins/channelrx/demodadsb/airlinelogos/ULC.bmp
new file mode 100644
index 000000000..e6fb8187c
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ULC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UNA.bmp b/plugins/channelrx/demodadsb/airlinelogos/UNA.bmp
new file mode 100644
index 000000000..1c3290c5e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UNA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/USC.bmp b/plugins/channelrx/demodadsb/airlinelogos/USC.bmp
new file mode 100644
index 000000000..a03968ea3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/USC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UTA.bmp b/plugins/channelrx/demodadsb/airlinelogos/UTA.bmp
index 3e0c36993..feda6fb80 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/UTA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/UTA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UVT.bmp b/plugins/channelrx/demodadsb/airlinelogos/UVT.bmp
new file mode 100644
index 000000000..9addc8bd1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UVT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/UWJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/UWJ.bmp
new file mode 100644
index 000000000..23de01e7d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/UWJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VAA.bmp b/plugins/channelrx/demodadsb/airlinelogos/VAA.bmp
new file mode 100644
index 000000000..cb568f276
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VAA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VAJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/VAJ.bmp
new file mode 100644
index 000000000..992a03088
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VAJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VBA.bmp b/plugins/channelrx/demodadsb/airlinelogos/VBA.bmp
new file mode 100644
index 000000000..c73036cb9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VBA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VCJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/VCJ.bmp
new file mode 100644
index 000000000..992a03088
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VCJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VDR.bmp b/plugins/channelrx/demodadsb/airlinelogos/VDR.bmp
new file mode 100644
index 000000000..f212994a8
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VDR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VEC.bmp b/plugins/channelrx/demodadsb/airlinelogos/VEC.bmp
new file mode 100644
index 000000000..7f1e528a3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VEC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VES.bmp b/plugins/channelrx/demodadsb/airlinelogos/VES.bmp
new file mode 100644
index 000000000..a956f0a33
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VES.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VET.bmp b/plugins/channelrx/demodadsb/airlinelogos/VET.bmp
new file mode 100644
index 000000000..ee3bef42f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VET.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VFC.bmp b/plugins/channelrx/demodadsb/airlinelogos/VFC.bmp
index c3e3c36b4..9a9beeb54 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/VFC.bmp and b/plugins/channelrx/demodadsb/airlinelogos/VFC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VJT.bmp b/plugins/channelrx/demodadsb/airlinelogos/VJT.bmp
new file mode 100644
index 000000000..316427f36
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VJT.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VKG.bmp b/plugins/channelrx/demodadsb/airlinelogos/VKG.bmp
index 96a199d42..efb555d6c 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/VKG.bmp and b/plugins/channelrx/demodadsb/airlinelogos/VKG.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VKGOLD.bmp b/plugins/channelrx/demodadsb/airlinelogos/VKGOLD.bmp
new file mode 100644
index 000000000..96a199d42
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VKGOLD.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VLJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/VLJ.bmp
new file mode 100644
index 000000000..4b5e09507
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VLJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VOC.bmp b/plugins/channelrx/demodadsb/airlinelogos/VOC.bmp
new file mode 100644
index 000000000..57d22a678
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VOC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VOI.bmp b/plugins/channelrx/demodadsb/airlinelogos/VOI.bmp
new file mode 100644
index 000000000..57d22a678
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VOI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VPC.bmp b/plugins/channelrx/demodadsb/airlinelogos/VPC.bmp
new file mode 100644
index 000000000..3c655f2d1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VPC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VPE.bmp b/plugins/channelrx/demodadsb/airlinelogos/VPE.bmp
new file mode 100644
index 000000000..63fcef24e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VPE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VTE.bmp b/plugins/channelrx/demodadsb/airlinelogos/VTE.bmp
new file mode 100644
index 000000000..220d0157d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VTE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VTS.bmp b/plugins/channelrx/demodadsb/airlinelogos/VTS.bmp
new file mode 100644
index 000000000..bdf82b71e
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VTS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VTU.bmp b/plugins/channelrx/demodadsb/airlinelogos/VTU.bmp
new file mode 100644
index 000000000..0e5c6ad28
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VTU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/VVV.bmp b/plugins/channelrx/demodadsb/airlinelogos/VVV.bmp
new file mode 100644
index 000000000..840d701e9
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/VVV.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WAA.bmp b/plugins/channelrx/demodadsb/airlinelogos/WAA.bmp
new file mode 100644
index 000000000..7ee4c0d44
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WAA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WAL.bmp b/plugins/channelrx/demodadsb/airlinelogos/WAL.bmp
new file mode 100644
index 000000000..36596f47d
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WAL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WAU.bmp b/plugins/channelrx/demodadsb/airlinelogos/WAU.bmp
new file mode 100644
index 000000000..a8555ab6f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WAU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WDE.bmp b/plugins/channelrx/demodadsb/airlinelogos/WDE.bmp
new file mode 100644
index 000000000..822c07c98
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WDE.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WGN.bmp b/plugins/channelrx/demodadsb/airlinelogos/WGN.bmp
new file mode 100644
index 000000000..952de4e76
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WGN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WHS.bmp b/plugins/channelrx/demodadsb/airlinelogos/WHS.bmp
new file mode 100644
index 000000000..f75b4fb40
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WHS.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WIA.bmp b/plugins/channelrx/demodadsb/airlinelogos/WIA.bmp
new file mode 100644
index 000000000..992c642c2
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WIA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WIL.bmp b/plugins/channelrx/demodadsb/airlinelogos/WIL.bmp
new file mode 100644
index 000000000..f39b852c6
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WIL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WJA.bmp b/plugins/channelrx/demodadsb/airlinelogos/WJA.bmp
index 7864926d0..5e7334c42 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/WJA.bmp and b/plugins/channelrx/demodadsb/airlinelogos/WJA.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WLB.bmp b/plugins/channelrx/demodadsb/airlinelogos/WLB.bmp
new file mode 100644
index 000000000..44b1e777a
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WLB.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WMN.bmp b/plugins/channelrx/demodadsb/airlinelogos/WMN.bmp
new file mode 100644
index 000000000..b2f1f0131
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WMN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WON.bmp b/plugins/channelrx/demodadsb/airlinelogos/WON.bmp
new file mode 100644
index 000000000..1c0238b36
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WON.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WORLD2FLY.bmp b/plugins/channelrx/demodadsb/airlinelogos/WORLD2FLY.bmp
new file mode 100644
index 000000000..30e05237f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WORLD2FLY.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WSN.bmp b/plugins/channelrx/demodadsb/airlinelogos/WSN.bmp
new file mode 100644
index 000000000..d2b17d8d3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WSN.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WSW.bmp b/plugins/channelrx/demodadsb/airlinelogos/WSW.bmp
new file mode 100644
index 000000000..b0cd965f1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WSW.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WWI.bmp b/plugins/channelrx/demodadsb/airlinelogos/WWI.bmp
new file mode 100644
index 000000000..c9574a036
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/WWI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/WZZ.bmp b/plugins/channelrx/demodadsb/airlinelogos/WZZ.bmp
index a8555ab6f..0a884aea1 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/WZZ.bmp and b/plugins/channelrx/demodadsb/airlinelogos/WZZ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/XAI.bmp b/plugins/channelrx/demodadsb/airlinelogos/XAI.bmp
new file mode 100644
index 000000000..4f7a72da5
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/XAI.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/XAU.bmp b/plugins/channelrx/demodadsb/airlinelogos/XAU.bmp
new file mode 100644
index 000000000..19eb7879f
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/XAU.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/XLK.bmp b/plugins/channelrx/demodadsb/airlinelogos/XLK.bmp
new file mode 100644
index 000000000..8dfffecd1
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/XLK.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/XOJ.bmp b/plugins/channelrx/demodadsb/airlinelogos/XOJ.bmp
new file mode 100644
index 000000000..4e4f604b3
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/XOJ.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/XRC.bmp b/plugins/channelrx/demodadsb/airlinelogos/XRC.bmp
new file mode 100644
index 000000000..ebcafce08
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/XRC.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/XRO.bmp b/plugins/channelrx/demodadsb/airlinelogos/XRO.bmp
new file mode 100644
index 000000000..1160b5a4b
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/XRO.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/YEL.bmp b/plugins/channelrx/demodadsb/airlinelogos/YEL.bmp
new file mode 100644
index 000000000..4a74ffe05
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/YEL.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/YZR.bmp b/plugins/channelrx/demodadsb/airlinelogos/YZR.bmp
index 5fa45d631..1e7cc1fed 100644
Binary files a/plugins/channelrx/demodadsb/airlinelogos/YZR.bmp and b/plugins/channelrx/demodadsb/airlinelogos/YZR.bmp differ
diff --git a/plugins/channelrx/demodadsb/airlinelogos/ZOM.bmp b/plugins/channelrx/demodadsb/airlinelogos/ZOM.bmp
new file mode 100644
index 000000000..be6949624
Binary files /dev/null and b/plugins/channelrx/demodadsb/airlinelogos/ZOM.bmp differ
diff --git a/plugins/channelrx/demodadsb/readme.md b/plugins/channelrx/demodadsb/readme.md
index 364e32fbb..514613426 100644
--- a/plugins/channelrx/demodadsb/readme.md
+++ b/plugins/channelrx/demodadsb/readme.md
@@ -133,7 +133,7 @@ If an ADS-B frame has not been received from an aircraft for 60 seconds, the air
* Double clicking in an Az/El cell will set the aircraft as the active target. The azimuth and elevation to the aicraft will be sent to a rotator controller plugin. The aircraft information box will be coloured green, rather than blue, on the map.
* Double clicking on any other cell in the table will centre the map on the corresponding aircraft.
-
Map
+
Map
The map displays aircraft locations and data geographically.
@@ -149,7 +149,8 @@ Aircraft are only placed upon the map when a position can be calculated, which c
* Left clicking the information box next to an aircraft will reveal more information. It can be closed by clicking it again.
* Left clicking the information box next to an airport will reveal ATC frequencies for the airport (if the OurAirports database has been downloaded.). This information box can be closed by left clicking on the airport identifier. Double clicking on one of the listed frequencies, will set it as the centre frequency on the selected SDRangel device set (15). The Az/El row gives the azimuth and elevation of the airport from the location set under Preferences > My Position. Double clicking on this row will set the airport as the active target.
-
Attribution
+
Attribution
Airline logos and flags are by Steve Hibberd from https://radarspotting.com
+
Map icons are by Alice Design, Alex Ahineev, Botho Willer, Verry Obito, Sean Maldjia, Tinashe Mugayi, Georgiana Ionescu, Andreas Vögele, Tom Fricker, Will Sullivan, Tim Tores, BGBOXXX Design, and Angriawan Ditya Zulkarnain from the Noun Project https://thenounproject.com/
diff --git a/plugins/channelrx/demodapt/CMakeLists.txt b/plugins/channelrx/demodapt/CMakeLists.txt
new file mode 100644
index 000000000..2eeacf6de
--- /dev/null
+++ b/plugins/channelrx/demodapt/CMakeLists.txt
@@ -0,0 +1,68 @@
+project(demodapt)
+
+set(demodapt_SOURCES
+ aptdemod.cpp
+ aptdemodsettings.cpp
+ aptdemodbaseband.cpp
+ aptdemodsink.cpp
+ aptdemodplugin.cpp
+ aptdemodwebapiadapter.cpp
+)
+
+set(demodapt_HEADERS
+ aptdemod.h
+ aptdemodsettings.h
+ aptdemodbaseband.h
+ aptdemodsink.h
+ aptdemodplugin.h
+ aptdemodwebapiadapter.h
+)
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
+ ${APT_INCLUDE_DIR}
+)
+
+if(NOT SERVER_MODE)
+ set(demodapt_SOURCES
+ ${demodapt_SOURCES}
+ aptdemodgui.cpp
+ aptdemodgui.ui
+ aptdemodsettingsdialog.cpp
+ aptdemodsettingsdialog.ui
+ icons.qrc
+ )
+ set(demodapt_HEADERS
+ ${demodapt_HEADERS}
+ aptdemodgui.h
+ aptdemodsettingsdialog.h
+ )
+
+ set(TARGET_NAME demodapt)
+ set(TARGET_LIB "Qt5::Widgets")
+ set(TARGET_LIB_GUI "sdrgui")
+ set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
+else()
+ set(TARGET_NAME demodaptsrv)
+ set(TARGET_LIB "")
+ set(TARGET_LIB_GUI "")
+ set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
+endif()
+
+add_library(${TARGET_NAME} SHARED
+ ${demodapt_SOURCES}
+)
+
+if(APT_EXTERNAL)
+ add_dependencies(${TARGET_NAME} apt)
+endif()
+
+target_link_libraries(${TARGET_NAME}
+ Qt5::Core
+ ${TARGET_LIB}
+ sdrbase
+ ${TARGET_LIB_GUI}
+ ${APT_LIBRARIES}
+)
+
+install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
diff --git a/plugins/channelrx/demodapt/aptdemod.cpp b/plugins/channelrx/demodapt/aptdemod.cpp
new file mode 100644
index 000000000..86f9f65c2
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemod.cpp
@@ -0,0 +1,851 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "aptdemod.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "SWGChannelSettings.h"
+#include "SWGAPTDemodSettings.h"
+#include "SWGChannelReport.h"
+#include "SWGChannelActions.h"
+#include "SWGMapItem.h"
+#include "SWGAPTDemodActions.h"
+
+#include "dsp/dspengine.h"
+#include "dsp/dspcommands.h"
+#include "device/deviceapi.h"
+#include "feature/feature.h"
+#include "util/db.h"
+#include "maincore.h"
+
+MESSAGE_CLASS_DEFINITION(APTDemod::MsgConfigureAPTDemod, Message)
+MESSAGE_CLASS_DEFINITION(APTDemod::MsgPixels, Message)
+MESSAGE_CLASS_DEFINITION(APTDemod::MsgImage, Message)
+MESSAGE_CLASS_DEFINITION(APTDemod::MsgResetDecoder, Message)
+
+const char * const APTDemod::m_channelIdURI = "sdrangel.channel.aptdemod";
+const char * const APTDemod::m_channelId = "APTDemod";
+
+APTDemod::APTDemod(DeviceAPI *deviceAPI) :
+ ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
+ m_deviceAPI(deviceAPI),
+ m_basebandSampleRate(0)
+{
+ setObjectName(m_channelId);
+
+ m_basebandSink = new APTDemodBaseband(this);
+ m_basebandSink->setMessageQueueToChannel(getInputMessageQueue());
+ m_basebandSink->moveToThread(&m_thread);
+
+ applySettings(m_settings, true);
+
+ m_deviceAPI->addChannelSink(this);
+ m_deviceAPI->addChannelSinkAPI(this);
+
+ m_networkManager = new QNetworkAccessManager();
+ connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
+
+ for (int y = 0; y < APT_MAX_HEIGHT; y++)
+ {
+ m_image.prow[y] = new float[APT_PROW_WIDTH];
+ m_tempImage.prow[y] = new float[APT_PROW_WIDTH];
+ }
+ resetDecoder();
+}
+
+APTDemod::~APTDemod()
+{
+ qDebug("APTDemod::~APTDemod");
+ disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
+ delete m_networkManager;
+ m_deviceAPI->removeChannelSinkAPI(this);
+ m_deviceAPI->removeChannelSink(this);
+
+ if (m_basebandSink->isRunning()) {
+ stop();
+ }
+
+ delete m_basebandSink;
+
+ for (int y = 0; y < APT_MAX_HEIGHT; y++)
+ {
+ delete m_image.prow[y];
+ delete m_tempImage.prow[y];
+ }
+}
+
+uint32_t APTDemod::getNumberOfDeviceStreams() const
+{
+ return m_deviceAPI->getNbSourceStreams();
+}
+
+void APTDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst)
+{
+ (void) firstOfBurst;
+ m_basebandSink->feed(begin, end);
+}
+
+void APTDemod::start()
+{
+ qDebug("APTDemod::start");
+
+ m_basebandSink->reset();
+ m_basebandSink->startWork();
+ m_thread.start();
+
+ DSPSignalNotification *dspMsg = new DSPSignalNotification(m_basebandSampleRate, m_centerFrequency);
+ m_basebandSink->getInputMessageQueue()->push(dspMsg);
+
+ APTDemodBaseband::MsgConfigureAPTDemodBaseband *msg = APTDemodBaseband::MsgConfigureAPTDemodBaseband::create(m_settings, true);
+ m_basebandSink->getInputMessageQueue()->push(msg);
+}
+
+void APTDemod::stop()
+{
+ qDebug("APTDemod::stop");
+ m_basebandSink->stopWork();
+ m_thread.quit();
+ m_thread.wait();
+}
+
+bool APTDemod::matchSatellite(const QString satelliteName)
+{
+ return m_settings.m_satelliteTrackerControl
+ && ( (satelliteName == m_settings.m_satelliteName)
+ || ( (m_settings.m_satelliteName == "All")
+ && ( (satelliteName == "NOAA 15")
+ || (satelliteName == "NOAA 18")
+ || (satelliteName == "NOAA 19"))));
+}
+
+bool APTDemod::handleMessage(const Message& cmd)
+{
+ if (MsgConfigureAPTDemod::match(cmd))
+ {
+ MsgConfigureAPTDemod& cfg = (MsgConfigureAPTDemod&) cmd;
+ qDebug() << "APTDemod::handleMessage: MsgConfigureAPTDemod";
+ applySettings(cfg.getSettings(), cfg.getForce());
+
+ return true;
+ }
+ else if (DSPSignalNotification::match(cmd))
+ {
+ DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
+ m_basebandSampleRate = notif.getSampleRate();
+ m_centerFrequency = notif.getCenterFrequency();
+ // Forward to the sink
+ DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
+ qDebug() << "APTDemod::handleMessage: DSPSignalNotification";
+ m_basebandSink->getInputMessageQueue()->push(rep);
+ // Forward to GUI if any
+ if (m_guiMessageQueue)
+ m_guiMessageQueue->push(new DSPSignalNotification(notif));
+
+ return true;
+ }
+ else if (APTDemod::MsgPixels::match(cmd))
+ {
+ const APTDemod::MsgPixels& pixelsMsg = (APTDemod::MsgPixels&) cmd;
+ const float *pixels = pixelsMsg.getPixels();
+ processPixels(pixels);
+ return true;
+ }
+ else if (APTDemod::MsgResetDecoder::match(cmd))
+ {
+ resetDecoder();
+ // Forward to sink
+ m_basebandSink->getInputMessageQueue()->push(APTDemod::MsgResetDecoder::create());
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void APTDemod::applySettings(const APTDemodSettings& settings, bool force)
+{
+ bool callProcessImage = false;
+
+ qDebug() << "APTDemod::applySettings:"
+ << " m_cropNoise: " << settings.m_cropNoise
+ << " m_denoise: " << settings.m_denoise
+ << " m_linearEqualise: " << settings.m_linearEqualise
+ << " m_histogramEqualise: " << settings.m_histogramEqualise
+ << " m_precipitationOverlay: " << settings.m_precipitationOverlay
+ << " m_flip: " << settings.m_flip
+ << " m_channels: " << settings.m_channels
+ << " m_decodeEnabled: " << settings.m_decodeEnabled
+ << " m_autoSave: " << settings.m_autoSave
+ << " m_autoSavePath: " << settings.m_autoSavePath
+ << " m_autoSaveMinScanLines: " << settings.m_autoSaveMinScanLines
+ << " m_streamIndex: " << settings.m_streamIndex
+ << " m_useReverseAPI: " << settings.m_useReverseAPI
+ << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
+ << " m_reverseAPIPort: " << settings.m_reverseAPIPort
+ << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
+ << " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
+ << " force: " << force;
+
+ QList reverseAPIKeys;
+
+ if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
+ reverseAPIKeys.append("inputFrequencyOffset");
+ }
+ if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
+ reverseAPIKeys.append("rfBandwidth");
+ }
+ if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) {
+ reverseAPIKeys.append("fmDeviation");
+ }
+ if ((settings.m_denoise != m_settings.m_denoise) || force) {
+ reverseAPIKeys.append("denoise");
+ }
+ if ((settings.m_linearEqualise != m_settings.m_linearEqualise) || force) {
+ reverseAPIKeys.append("linearEqualise");
+ }
+ if ((settings.m_histogramEqualise != m_settings.m_histogramEqualise) || force) {
+ reverseAPIKeys.append("histogramEqualise");
+ }
+ if ((settings.m_precipitationOverlay != m_settings.m_precipitationOverlay) || force) {
+ reverseAPIKeys.append("precipitationOverlay");
+ }
+ if ((settings.m_flip != m_settings.m_flip) || force) {
+ reverseAPIKeys.append("flip");
+ }
+ if ((settings.m_channels != m_settings.m_channels) || force) {
+ reverseAPIKeys.append("channels");
+ }
+ if ((settings.m_decodeEnabled != m_settings.m_decodeEnabled) || force) {
+ reverseAPIKeys.append("decodeEnabled");
+ }
+ if ((settings.m_autoSave != m_settings.m_autoSave) || force) {
+ reverseAPIKeys.append("autoSave");
+ }
+ if ((settings.m_autoSavePath != m_settings.m_autoSavePath) || force) {
+ reverseAPIKeys.append("autoSavePath");
+ }
+ if ((settings.m_autoSaveMinScanLines != m_settings.m_autoSaveMinScanLines) || force) {
+ reverseAPIKeys.append("autoSaveMinScanLines");
+ }
+
+ if (m_settings.m_streamIndex != settings.m_streamIndex)
+ {
+ if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
+ {
+ m_deviceAPI->removeChannelSinkAPI(this);
+ m_deviceAPI->removeChannelSink(this, m_settings.m_streamIndex);
+ m_deviceAPI->addChannelSink(this, settings.m_streamIndex);
+ m_deviceAPI->addChannelSinkAPI(this);
+ }
+
+ reverseAPIKeys.append("streamIndex");
+ }
+
+ APTDemodBaseband::MsgConfigureAPTDemodBaseband *msg = APTDemodBaseband::MsgConfigureAPTDemodBaseband::create(settings, force);
+ m_basebandSink->getInputMessageQueue()->push(msg);
+
+ if (settings.m_useReverseAPI)
+ {
+ bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
+ (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
+ (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
+ (m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) ||
+ (m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex);
+ webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
+ }
+
+ if ((settings.m_cropNoise != m_settings.m_cropNoise) ||
+ (settings.m_denoise != m_settings.m_denoise) ||
+ (settings.m_linearEqualise != m_settings.m_linearEqualise) ||
+ (settings.m_histogramEqualise != m_settings.m_histogramEqualise) ||
+ (settings.m_precipitationOverlay != m_settings.m_precipitationOverlay) ||
+ (settings.m_flip != m_settings.m_flip) ||
+ (settings.m_channels != m_settings.m_channels))
+ {
+ // Call after settings have been applied
+ callProcessImage = true;
+ }
+
+ m_settings = settings;
+
+ if (callProcessImage)
+ sendImageToGUI();
+}
+
+QByteArray APTDemod::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool APTDemod::deserialize(const QByteArray& data)
+{
+ if (m_settings.deserialize(data))
+ {
+ MsgConfigureAPTDemod *msg = MsgConfigureAPTDemod::create(m_settings, true);
+ m_inputMessageQueue.push(msg);
+ return true;
+ }
+ else
+ {
+ m_settings.resetToDefaults();
+ MsgConfigureAPTDemod *msg = MsgConfigureAPTDemod::create(m_settings, true);
+ m_inputMessageQueue.push(msg);
+ return false;
+ }
+}
+
+int APTDemod::webapiSettingsGet(
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage)
+{
+ (void) errorMessage;
+ response.setAptDemodSettings(new SWGSDRangel::SWGAPTDemodSettings());
+ response.getAptDemodSettings()->init();
+ webapiFormatChannelSettings(response, m_settings);
+ return 200;
+}
+
+int APTDemod::webapiSettingsPutPatch(
+ bool force,
+ const QStringList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage)
+{
+ (void) errorMessage;
+ APTDemodSettings settings = m_settings;
+ webapiUpdateChannelSettings(settings, channelSettingsKeys, response);
+
+ MsgConfigureAPTDemod *msg = MsgConfigureAPTDemod::create(settings, force);
+ m_inputMessageQueue.push(msg);
+
+ qDebug("APTDemod::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
+ if (m_guiMessageQueue) // forward to GUI if any
+ {
+ MsgConfigureAPTDemod *msgToGUI = MsgConfigureAPTDemod::create(settings, force);
+ m_guiMessageQueue->push(msgToGUI);
+ }
+
+ webapiFormatChannelSettings(response, settings);
+
+ return 200;
+}
+
+void APTDemod::webapiUpdateChannelSettings(
+ APTDemodSettings& settings,
+ const QStringList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings& response)
+{
+ if (channelSettingsKeys.contains("inputFrequencyOffset")) {
+ settings.m_inputFrequencyOffset = response.getAptDemodSettings()->getInputFrequencyOffset();
+ }
+ if (channelSettingsKeys.contains("fmDeviation")) {
+ settings.m_fmDeviation = response.getAptDemodSettings()->getFmDeviation();
+ }
+ if (channelSettingsKeys.contains("rfBandwidth")) {
+ settings.m_rfBandwidth = response.getAptDemodSettings()->getRfBandwidth();
+ }
+ if (channelSettingsKeys.contains("cropNoise")) {
+ settings.m_cropNoise = response.getAptDemodSettings()->getCropNoise();
+ }
+ if (channelSettingsKeys.contains("denoise")) {
+ settings.m_denoise = response.getAptDemodSettings()->getDenoise();
+ }
+ if (channelSettingsKeys.contains("linearEqualise")) {
+ settings.m_linearEqualise = response.getAptDemodSettings()->getLinearEqualise();
+ }
+ if (channelSettingsKeys.contains("histogramEqualise")) {
+ settings.m_histogramEqualise = response.getAptDemodSettings()->getHistogramEqualise();
+ }
+ if (channelSettingsKeys.contains("precipitationOverlay")) {
+ settings.m_precipitationOverlay = response.getAptDemodSettings()->getPrecipitationOverlay();
+ }
+ if (channelSettingsKeys.contains("flip")) {
+ settings.m_flip = response.getAptDemodSettings()->getFlip();
+ }
+ if (channelSettingsKeys.contains("channels")) {
+ settings.m_channels = (APTDemodSettings::ChannelSelection)response.getAptDemodSettings()->getChannels();
+ }
+ if (channelSettingsKeys.contains("decodeEnabled")) {
+ settings.m_decodeEnabled = response.getAptDemodSettings()->getDecodeEnabled();
+ }
+ if (channelSettingsKeys.contains("autoSave")) {
+ settings.m_autoSave = response.getAptDemodSettings()->getAutoSave();
+ }
+ if (channelSettingsKeys.contains("autoSavePath")) {
+ settings.m_autoSavePath = *response.getAptDemodSettings()->getAutoSavePath();
+ }
+ if (channelSettingsKeys.contains("autoSaveMinScanLines")) {
+ settings.m_autoSaveMinScanLines = response.getAptDemodSettings()->getAutoSaveMinScanLines();
+ }
+ if (channelSettingsKeys.contains("rgbColor")) {
+ settings.m_rgbColor = response.getAptDemodSettings()->getRgbColor();
+ }
+ if (channelSettingsKeys.contains("title")) {
+ settings.m_title = *response.getAptDemodSettings()->getTitle();
+ }
+ if (channelSettingsKeys.contains("streamIndex")) {
+ settings.m_streamIndex = response.getAptDemodSettings()->getStreamIndex();
+ }
+ if (channelSettingsKeys.contains("useReverseAPI")) {
+ settings.m_useReverseAPI = response.getAptDemodSettings()->getUseReverseApi() != 0;
+ }
+ if (channelSettingsKeys.contains("reverseAPIAddress")) {
+ settings.m_reverseAPIAddress = *response.getAptDemodSettings()->getReverseApiAddress();
+ }
+ if (channelSettingsKeys.contains("reverseAPIPort")) {
+ settings.m_reverseAPIPort = response.getAptDemodSettings()->getReverseApiPort();
+ }
+ if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
+ settings.m_reverseAPIDeviceIndex = response.getAptDemodSettings()->getReverseApiDeviceIndex();
+ }
+ if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
+ settings.m_reverseAPIChannelIndex = response.getAptDemodSettings()->getReverseApiChannelIndex();
+ }
+}
+
+void APTDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const APTDemodSettings& settings)
+{
+ response.getAptDemodSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
+ response.getAptDemodSettings()->setRfBandwidth(settings.m_rfBandwidth);
+ response.getAptDemodSettings()->setFmDeviation(settings.m_fmDeviation);
+ response.getAptDemodSettings()->setCropNoise(settings.m_cropNoise);
+ response.getAptDemodSettings()->setCropNoise(settings.m_denoise);
+ response.getAptDemodSettings()->setLinearEqualise(settings.m_linearEqualise);
+ response.getAptDemodSettings()->setHistogramEqualise(settings.m_histogramEqualise);
+ response.getAptDemodSettings()->setPrecipitationOverlay(settings.m_precipitationOverlay);
+ response.getAptDemodSettings()->setFlip(settings.m_flip);
+ response.getAptDemodSettings()->setChannels((int)settings.m_channels);
+ response.getAptDemodSettings()->setDecodeEnabled(settings.m_decodeEnabled);
+ response.getAptDemodSettings()->setAutoSave(settings.m_autoSave);
+ response.getAptDemodSettings()->setAutoSavePath(new QString(settings.m_autoSavePath));
+ response.getAptDemodSettings()->setAutoSaveMinScanLines(settings.m_autoSaveMinScanLines);
+
+ response.getAptDemodSettings()->setRgbColor(settings.m_rgbColor);
+
+ if (response.getAptDemodSettings()->getTitle()) {
+ *response.getAptDemodSettings()->getTitle() = settings.m_title;
+ } else {
+ response.getAptDemodSettings()->setTitle(new QString(settings.m_title));
+ }
+
+ response.getAptDemodSettings()->setStreamIndex(settings.m_streamIndex);
+ response.getAptDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
+
+ if (response.getAptDemodSettings()->getReverseApiAddress()) {
+ *response.getAptDemodSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
+ } else {
+ response.getAptDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
+ }
+
+ response.getAptDemodSettings()->setReverseApiPort(settings.m_reverseAPIPort);
+ response.getAptDemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
+ response.getAptDemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
+}
+
+void APTDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const APTDemodSettings& settings, bool force)
+{
+ SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
+ webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
+
+ QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
+ .arg(settings.m_reverseAPIAddress)
+ .arg(settings.m_reverseAPIPort)
+ .arg(settings.m_reverseAPIDeviceIndex)
+ .arg(settings.m_reverseAPIChannelIndex);
+ m_networkRequest.setUrl(QUrl(channelSettingsURL));
+ m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ QBuffer *buffer = new QBuffer();
+ buffer->open((QBuffer::ReadWrite));
+ buffer->write(swgChannelSettings->asJson().toUtf8());
+ buffer->seek(0);
+
+ // Always use PATCH to avoid passing reverse API settings
+ QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
+ buffer->setParent(reply);
+
+ delete swgChannelSettings;
+}
+
+void APTDemod::webapiFormatChannelSettings(
+ QList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings *swgChannelSettings,
+ const APTDemodSettings& settings,
+ bool force
+)
+{
+ swgChannelSettings->setDirection(0); // Single sink (Rx)
+ swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
+ swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
+ swgChannelSettings->setChannelType(new QString("APTDemod"));
+ swgChannelSettings->setAptDemodSettings(new SWGSDRangel::SWGAPTDemodSettings());
+ SWGSDRangel::SWGAPTDemodSettings *swgAPTDemodSettings = swgChannelSettings->getAptDemodSettings();
+
+ // transfer data that has been modified. When force is on transfer all data except reverse API data
+
+ if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
+ swgAPTDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
+ }
+ if (channelSettingsKeys.contains("rfBandwidth") || force) {
+ swgAPTDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
+ }
+ if (channelSettingsKeys.contains("fmDeviation") || force) {
+ swgAPTDemodSettings->setFmDeviation(settings.m_fmDeviation);
+ }
+ if (channelSettingsKeys.contains("cropNoise") || force) {
+ swgAPTDemodSettings->setCropNoise(settings.m_cropNoise);
+ }
+ if (channelSettingsKeys.contains("denoise") || force) {
+ swgAPTDemodSettings->setDenoise(settings.m_denoise);
+ }
+ if (channelSettingsKeys.contains("linearEqualise") || force) {
+ swgAPTDemodSettings->setLinearEqualise(settings.m_linearEqualise);
+ }
+ if (channelSettingsKeys.contains("histogramEqualise") || force) {
+ swgAPTDemodSettings->setHistogramEqualise(settings.m_histogramEqualise);
+ }
+ if (channelSettingsKeys.contains("precipitationOverlay") || force) {
+ swgAPTDemodSettings->setPrecipitationOverlay(settings.m_precipitationOverlay);
+ }
+ if (channelSettingsKeys.contains("flip") || force) {
+ swgAPTDemodSettings->setFlip(settings.m_flip);
+ }
+ if (channelSettingsKeys.contains("channels") || force) {
+ swgAPTDemodSettings->setChannels((int)settings.m_channels);
+ }
+ if (channelSettingsKeys.contains("decodeEnabled") || force) {
+ swgAPTDemodSettings->setDecodeEnabled(settings.m_decodeEnabled);
+ }
+ if (channelSettingsKeys.contains("m_autoSave") || force) {
+ swgAPTDemodSettings->setAutoSave(settings.m_autoSave);
+ }
+ if (channelSettingsKeys.contains("m_autoSavePath") || force) {
+ swgAPTDemodSettings->setAutoSavePath(new QString(settings.m_autoSavePath));
+ }
+ if (channelSettingsKeys.contains("m_autoSaveMinScanLines") || force) {
+ swgAPTDemodSettings->setAutoSaveMinScanLines(settings.m_autoSaveMinScanLines);
+ }
+ if (channelSettingsKeys.contains("rgbColor") || force) {
+ swgAPTDemodSettings->setRgbColor(settings.m_rgbColor);
+ }
+ if (channelSettingsKeys.contains("title") || force) {
+ swgAPTDemodSettings->setTitle(new QString(settings.m_title));
+ }
+ if (channelSettingsKeys.contains("streamIndex") || force) {
+ swgAPTDemodSettings->setStreamIndex(settings.m_streamIndex);
+ }
+}
+
+int APTDemod::webapiActionsPost(
+ const QStringList& channelActionsKeys,
+ SWGSDRangel::SWGChannelActions& query,
+ QString& errorMessage)
+{
+ SWGSDRangel::SWGAPTDemodActions *swgAPTDemodActions = query.getAptDemodActions();
+
+ if (swgAPTDemodActions)
+ {
+ if (channelActionsKeys.contains("aos"))
+ {
+ qDebug() << "Aos action";
+ SWGSDRangel::SWGAPTDemodActions_aos* aos = swgAPTDemodActions->getAos();
+ QString *satelliteName = aos->getSatelliteName();
+ if (satelliteName != nullptr)
+ {
+ qDebug() << "sat " << *satelliteName;
+ if (matchSatellite(*satelliteName))
+ {
+ qDebug() << "Matched sat";
+ // Reset for new pass
+ resetDecoder();
+ m_basebandSink->getInputMessageQueue()->push(APTDemod::MsgResetDecoder::create());
+
+ // Save satellite name
+ m_satelliteName = *satelliteName;
+
+ // Enable decoder and set direction of pass
+ APTDemodSettings settings = m_settings;
+ settings.m_decodeEnabled = true;
+ settings.m_flip = !aos->getNorthToSouthPass();
+ qDebug() << "Sending settings";
+ m_inputMessageQueue.push(MsgConfigureAPTDemod::create(settings, false));
+ if (m_guiMessageQueue)
+ m_guiMessageQueue->push(MsgConfigureAPTDemod::create(settings, false));
+ }
+
+ return 202;
+ }
+ else
+ {
+ errorMessage = "Missing satellite name";
+ return 400;
+ }
+ }
+ else if (channelActionsKeys.contains("los"))
+ {
+ SWGSDRangel::SWGAPTDemodActions_los* los = swgAPTDemodActions->getLos();
+ QString *satelliteName = los->getSatelliteName();
+ if (satelliteName != nullptr)
+ {
+ if (matchSatellite(*satelliteName))
+ {
+ // Save image
+ if (m_settings.m_autoSave)
+ saveImageToDisk();
+ // Disable decoder
+ APTDemodSettings settings = m_settings;
+ settings.m_decodeEnabled = false;
+ m_inputMessageQueue.push(MsgConfigureAPTDemod::create(settings, false));
+ if (m_guiMessageQueue)
+ m_guiMessageQueue->push(MsgConfigureAPTDemod::create(settings, false));
+ }
+
+ return 202;
+ }
+ else
+ {
+ errorMessage = "Missing satellite name";
+ return 400;
+ }
+ }
+ else
+ {
+ errorMessage = "Unknown action";
+ return 400;
+ }
+ }
+ else
+ {
+ errorMessage = "Missing APTDemodActions in query";
+ return 400;
+ }
+}
+
+void APTDemod::networkManagerFinished(QNetworkReply *reply)
+{
+ QNetworkReply::NetworkError replyError = reply->error();
+
+ if (replyError)
+ {
+ qWarning() << "APTDemod::networkManagerFinished:"
+ << " error(" << (int) replyError
+ << "): " << replyError
+ << ": " << reply->errorString();
+ }
+ else
+ {
+ QString answer = reply->readAll();
+ answer.chop(1); // remove last \n
+ qDebug("APTDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
+ }
+
+ reply->deleteLater();
+}
+
+void APTDemod::resetDecoder()
+{
+ m_image.nrow = 0;
+ m_tempImage.nrow = 0;
+ m_greyImage = QImage(APT_IMG_WIDTH, APT_MAX_HEIGHT, QImage::Format_Grayscale8);
+ m_greyImage.fill(0);
+ m_colourImage = QImage(APT_IMG_WIDTH, APT_MAX_HEIGHT, QImage::Format_RGB888);
+ m_colourImage.fill(0);
+ m_satelliteName = "";
+}
+
+void APTDemod::processPixels(const float *pixels)
+{
+ memcpy(m_image.prow[m_image.nrow], pixels, sizeof(float) * APT_PROW_WIDTH);
+ m_image.nrow++;
+ sendImageToGUI();
+}
+
+static void copyImage(apt_image_t *dst, apt_image_t *src)
+{
+ dst->nrow = src->nrow;
+ dst->zenith = src->zenith;
+ dst->chA = src->chA;
+ dst->chB = src->chB;
+ for (int i = 0; i < src->nrow; i++)
+ memcpy(dst->prow[i], src->prow[i], sizeof(float) * APT_PROW_WIDTH);
+}
+
+static uchar roundAndClip(float p)
+{
+ int q = (int)round(p);
+ if (q > 255)
+ q = 255;
+ else if (q < 0)
+ q = 0;
+ return q;
+}
+
+QImage APTDemod::extractImage(QImage image)
+{
+ if (m_settings.m_channels == APTDemodSettings::BOTH_CHANNELS)
+ return image.copy(0, 0, APT_IMG_WIDTH, m_tempImage.nrow);
+ else if (m_settings.m_channels == APTDemodSettings::CHANNEL_A)
+ return image.copy(APT_CHA_OFFSET, 0, APT_CH_WIDTH, m_tempImage.nrow);
+ else
+ return image.copy(APT_CHB_OFFSET, 0, APT_CH_WIDTH, m_tempImage.nrow);
+}
+
+QImage APTDemod::processImage(QStringList& imageTypes)
+{
+ copyImage(&m_tempImage, &m_image);
+
+ // Calibrate channels according to wavelength
+ if (m_tempImage.nrow >= APT_CALIBRATION_ROWS)
+ {
+ m_tempImage.chA = apt_calibrate(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH);
+ m_tempImage.chB = apt_calibrate(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH);
+ QStringList channelTypes({
+ "", // Unknown
+ "Visible (0.58-0.68 um)",
+ "Near-IR (0.725-1.0 um)",
+ "Near-IR (1.58-1.64 um)",
+ "Mid-infrared (3.55-3.93 um)",
+ "Thermal-infrared (10.3-11.3 um)",
+ "Thermal-infrared (11.5-12.5 um)"
+ });
+
+ imageTypes.append(channelTypes[m_tempImage.chA]);
+ imageTypes.append(channelTypes[m_tempImage.chB]);
+ }
+
+ // Crop noise due to low elevation at top and bottom of image
+ if (m_settings.m_cropNoise)
+ m_tempImage.zenith -= apt_cropNoise(&m_tempImage);
+
+ // Denoise filter
+ if (m_settings.m_denoise)
+ {
+ apt_denoise(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH);
+ apt_denoise(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH);
+ }
+
+ // Flip image if satellite pass is North to South
+ if (m_settings.m_flip)
+ {
+ apt_flipImage(&m_tempImage, APT_CH_WIDTH, APT_CHA_OFFSET);
+ apt_flipImage(&m_tempImage, APT_CH_WIDTH, APT_CHB_OFFSET);
+ }
+
+ // Linear equalise to improve contrast
+ if (m_settings.m_linearEqualise)
+ {
+ apt_linearEnhance(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH);
+ apt_linearEnhance(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH);
+ }
+
+ // Histogram equalise to improve contrast
+ if (m_settings.m_histogramEqualise)
+ {
+ apt_histogramEqualise(m_tempImage.prow, m_tempImage.nrow, APT_CHA_OFFSET, APT_CH_WIDTH);
+ apt_histogramEqualise(m_tempImage.prow, m_tempImage.nrow, APT_CHB_OFFSET, APT_CH_WIDTH);
+ }
+
+ if (m_settings.m_precipitationOverlay)
+ {
+ // Overlay precipitation
+ for (int r = 0; r < m_tempImage.nrow; r++)
+ {
+ uchar *l = m_colourImage.scanLine(r);
+ for (int i = 0; i < APT_IMG_WIDTH; i++)
+ {
+ float p = m_tempImage.prow[r][i];
+
+ if ((i >= APT_CHB_OFFSET) && (i < APT_CHB_OFFSET + APT_CH_WIDTH) && (p >= 198))
+ {
+ apt_rgb_t rgb = apt_applyPalette(apt_PrecipPalette, p - 198);
+ // Negative float values get converted to positive uchars here
+ l[i*3] = (uchar)rgb.r;
+ l[i*3+1] = (uchar)rgb.g;
+ l[i*3+2] = (uchar)rgb.b;
+ int a = i - APT_CHB_OFFSET + APT_CHA_OFFSET;
+ l[a*3] = (uchar)rgb.r;
+ l[a*3+1] = (uchar)rgb.g;
+ l[a*3+2] = (uchar)rgb.b;
+ }
+ else
+ {
+ uchar q = roundAndClip(p);
+ l[i*3] = q;
+ l[i*3+1] = q;
+ l[i*3+2] = q;
+ }
+ }
+ }
+ return extractImage(m_colourImage);
+ }
+ else
+ {
+ for (int r = 0; r < m_tempImage.nrow; r++)
+ {
+ uchar *l = m_greyImage.scanLine(r);
+ for (int i = 0; i < APT_IMG_WIDTH; i++)
+ {
+ float p = m_tempImage.prow[r][i];
+ l[i] = roundAndClip(p);
+ }
+ }
+ return extractImage(m_greyImage);
+ }
+}
+
+void APTDemod::sendImageToGUI()
+{
+ // Send image to GUI
+ if (getMessageQueueToGUI())
+ {
+ QStringList imageTypes;
+ QImage image = processImage(imageTypes);
+ getMessageQueueToGUI()->push(APTDemod::MsgImage::create(image, imageTypes, m_satelliteName));
+ }
+}
+
+void APTDemod::saveImageToDisk()
+{
+ QStringList imageTypes;
+ QImage image = processImage(imageTypes);
+ if (image.height() >= m_settings.m_autoSaveMinScanLines)
+ {
+ QString filename;
+ QDateTime datetime = QDateTime::currentDateTime();
+ filename = QString("apt_%1_%2.png").arg(m_satelliteName).arg(datetime.toString("yyyyMMdd_hhmm"));
+ if (!m_settings.m_autoSavePath.isEmpty())
+ {
+ if (m_settings.m_autoSavePath.endsWith('/'))
+ filename = m_settings.m_autoSavePath + filename;
+ else
+ filename = m_settings.m_autoSavePath + '/' + filename;
+ }
+ if (!image.save(filename))
+ qCritical() << "Failed to save APT image to: " << filename;
+ }
+}
diff --git a/plugins/channelrx/demodapt/aptdemod.h b/plugins/channelrx/demodapt/aptdemod.h
new file mode 100644
index 000000000..f38341e6a
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemod.h
@@ -0,0 +1,242 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMOD_H
+#define INCLUDE_APTDEMOD_H
+
+#include
+
+#include
+#include
+#include
+
+#include
+
+#include "dsp/basebandsamplesink.h"
+#include "channel/channelapi.h"
+#include "util/message.h"
+
+#include "aptdemodbaseband.h"
+#include "aptdemodsettings.h"
+
+class QNetworkAccessManager;
+class QNetworkReply;
+class QThread;
+class DeviceAPI;
+
+class APTDemod : public BasebandSampleSink, public ChannelAPI {
+ Q_OBJECT
+public:
+ class MsgConfigureAPTDemod : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const APTDemodSettings& getSettings() const { return m_settings; }
+ bool getForce() const { return m_force; }
+
+ static MsgConfigureAPTDemod* create(const APTDemodSettings& settings, bool force)
+ {
+ return new MsgConfigureAPTDemod(settings, force);
+ }
+
+ private:
+ APTDemodSettings m_settings;
+ bool m_force;
+
+ MsgConfigureAPTDemod(const APTDemodSettings& settings, bool force) :
+ Message(),
+ m_settings(settings),
+ m_force(force)
+ { }
+ };
+
+ // One row of pixels from sink
+ class MsgPixels : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const float *getPixels() const { return m_pixels; }
+ int getZenith() const { return m_zenith; }
+
+ static MsgPixels* create(const float *pixels, int zenith)
+ {
+ return new MsgPixels(pixels, zenith);
+ }
+
+ private:
+ float m_pixels[APT_PROW_WIDTH];
+ int m_zenith;
+
+ MsgPixels(const float *pixels, int zenith) :
+ Message(),
+ m_zenith(zenith)
+ {
+ memcpy(m_pixels, pixels, sizeof(m_pixels));
+ }
+ };
+
+ // Processed image to be sent to GUI
+ class MsgImage : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const QImage getImage() const { return m_image; }
+ const QStringList getImageTypes() const { return m_imageTypes; }
+ const QString getSatelliteName() const { return m_satelliteName; }
+
+ static MsgImage* create(const QImage image, const QStringList imageTypes, const QString satelliteName)
+ {
+ return new MsgImage(image, imageTypes, satelliteName);
+ }
+
+ private:
+ QImage m_image;
+ QStringList m_imageTypes;
+ QString m_satelliteName;
+
+ MsgImage(const QImage image, const QStringList imageTypes, const QString satelliteName) :
+ Message(),
+ m_image(image),
+ m_imageTypes(imageTypes),
+ m_satelliteName(satelliteName)
+ {
+ }
+ };
+
+ // Sent from GUI to reset decoder
+ class MsgResetDecoder : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ static MsgResetDecoder* create()
+ {
+ return new MsgResetDecoder();
+ }
+
+ private:
+
+ MsgResetDecoder() :
+ Message()
+ {
+ }
+ };
+
+ APTDemod(DeviceAPI *deviceAPI);
+ virtual ~APTDemod();
+ virtual void destroy() { delete this; }
+
+ using BasebandSampleSink::feed;
+ virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
+ virtual void start();
+ virtual void stop();
+ virtual bool handleMessage(const Message& cmd);
+
+ virtual void getIdentifier(QString& id) { id = objectName(); }
+ virtual const QString& getURI() const { return getName(); }
+ virtual void getTitle(QString& title) { title = m_settings.m_title; }
+ virtual qint64 getCenterFrequency() const { return 0; }
+
+ virtual QByteArray serialize() const;
+ virtual bool deserialize(const QByteArray& data);
+
+ virtual int getNbSinkStreams() const { return 1; }
+ virtual int getNbSourceStreams() const { return 0; }
+
+ virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const
+ {
+ (void) streamIndex;
+ (void) sinkElseSource;
+ return 0;
+ }
+
+ virtual int webapiSettingsGet(
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage);
+
+ virtual int webapiSettingsPutPatch(
+ bool force,
+ const QStringList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage);
+
+ virtual int webapiActionsPost(
+ const QStringList& channelActionsKeys,
+ SWGSDRangel::SWGChannelActions& query,
+ QString& errorMessage);
+
+ static void webapiFormatChannelSettings(
+ SWGSDRangel::SWGChannelSettings& response,
+ const APTDemodSettings& settings);
+
+ static void webapiUpdateChannelSettings(
+ APTDemodSettings& settings,
+ const QStringList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings& response);
+
+ double getMagSq() const { return m_basebandSink->getMagSq(); }
+
+ void getMagSqLevels(double& avg, double& peak, int& nbSamples) {
+ m_basebandSink->getMagSqLevels(avg, peak, nbSamples);
+ }
+
+ uint32_t getNumberOfDeviceStreams() const;
+
+ static const char * const m_channelIdURI;
+ static const char * const m_channelId;
+
+private:
+ DeviceAPI *m_deviceAPI;
+ QThread m_thread;
+ APTDemodBaseband* m_basebandSink;
+ APTDemodSettings m_settings;
+ int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
+ qint64 m_centerFrequency;
+
+ QNetworkAccessManager *m_networkManager;
+ QNetworkRequest m_networkRequest;
+
+ // Image buffers
+ apt_image_t m_image; // Received image
+ apt_image_t m_tempImage; // Processed image
+ QImage m_greyImage;
+ QImage m_colourImage;
+ QString m_satelliteName;
+
+ void applySettings(const APTDemodSettings& settings, bool force = false);
+ void webapiReverseSendSettings(QList& channelSettingsKeys, const APTDemodSettings& settings, bool force);
+ void webapiFormatChannelSettings(
+ QList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings *swgChannelSettings,
+ const APTDemodSettings& settings,
+ bool force
+ );
+
+ bool matchSatellite(const QString satelliteName);
+ void resetDecoder();
+ void processPixels(const float *pixels);
+ QImage extractImage(QImage image);
+ QImage processImage(QStringList& imageTypes);
+ void sendImageToGUI();
+ void saveImageToDisk();
+
+private slots:
+ void networkManagerFinished(QNetworkReply *reply);
+
+};
+
+#endif // INCLUDE_APTDEMOD_H
diff --git a/plugins/channelrx/demodapt/aptdemodbaseband.cpp b/plugins/channelrx/demodapt/aptdemodbaseband.cpp
new file mode 100644
index 000000000..9a700a1b7
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodbaseband.cpp
@@ -0,0 +1,177 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include "dsp/dspengine.h"
+#include "dsp/dspcommands.h"
+#include "dsp/downchannelizer.h"
+
+#include "aptdemodbaseband.h"
+#include "aptdemod.h"
+
+MESSAGE_CLASS_DEFINITION(APTDemodBaseband::MsgConfigureAPTDemodBaseband, Message)
+
+APTDemodBaseband::APTDemodBaseband(APTDemod *packetDemod) :
+ m_sink(packetDemod),
+ m_running(false),
+ m_mutex(QMutex::Recursive)
+{
+ qDebug("APTDemodBaseband::APTDemodBaseband");
+
+ m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000));
+ m_channelizer = new DownChannelizer(&m_sink);
+}
+
+APTDemodBaseband::~APTDemodBaseband()
+{
+ m_inputMessageQueue.clear();
+
+ delete m_channelizer;
+}
+
+void APTDemodBaseband::reset()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ m_inputMessageQueue.clear();
+ m_sampleFifo.reset();
+}
+
+void APTDemodBaseband::startWork()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
+ QObject::connect(
+ &m_sampleFifo,
+ &SampleSinkFifo::dataReady,
+ this,
+ &APTDemodBaseband::handleData,
+ Qt::QueuedConnection
+ );
+ m_running = true;
+}
+
+void APTDemodBaseband::stopWork()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
+ QObject::disconnect(
+ &m_sampleFifo,
+ &SampleSinkFifo::dataReady,
+ this,
+ &APTDemodBaseband::handleData
+ );
+ m_running = false;
+}
+
+void APTDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
+{
+ m_sampleFifo.write(begin, end);
+}
+
+void APTDemodBaseband::handleData()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+
+ while ((m_sampleFifo.fill() > 0) && (m_inputMessageQueue.size() == 0))
+ {
+ SampleVector::iterator part1begin;
+ SampleVector::iterator part1end;
+ SampleVector::iterator part2begin;
+ SampleVector::iterator part2end;
+
+ std::size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end);
+
+ // first part of FIFO data
+ if (part1begin != part1end) {
+ m_channelizer->feed(part1begin, part1end);
+ }
+
+ // second part of FIFO data (used when block wraps around)
+ if(part2begin != part2end) {
+ m_channelizer->feed(part2begin, part2end);
+ }
+
+ m_sampleFifo.readCommit((unsigned int) count);
+ }
+}
+
+void APTDemodBaseband::handleInputMessages()
+{
+ Message* message;
+
+ while ((message = m_inputMessageQueue.pop()) != nullptr)
+ {
+ if (handleMessage(*message)) {
+ delete message;
+ }
+ }
+}
+
+bool APTDemodBaseband::handleMessage(const Message& cmd)
+{
+ qDebug() << "APTDemodBaseband::handleMessage";
+ if (MsgConfigureAPTDemodBaseband::match(cmd))
+ {
+ QMutexLocker mutexLocker(&m_mutex);
+ MsgConfigureAPTDemodBaseband& cfg = (MsgConfigureAPTDemodBaseband&) cmd;
+ qDebug() << "APTDemodBaseband::handleMessage: MsgConfigureAPTDemodBaseband";
+
+ applySettings(cfg.getSettings(), cfg.getForce());
+
+ return true;
+ }
+ else if (DSPSignalNotification::match(cmd))
+ {
+ QMutexLocker mutexLocker(&m_mutex);
+ DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
+ qDebug() << "APTDemodBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
+ setBasebandSampleRate(notif.getSampleRate());
+ m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate()));
+
+ return true;
+ }
+ else if (APTDemod::MsgResetDecoder::match(cmd))
+ {
+ m_sink.resetDecoder();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void APTDemodBaseband::applySettings(const APTDemodSettings& settings, bool force)
+{
+ if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
+ {
+ m_channelizer->setChannelization(APTDEMOD_AUDIO_SAMPLE_RATE, settings.m_inputFrequencyOffset);
+ m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
+ }
+
+ m_sink.applySettings(settings, force);
+
+ m_settings = settings;
+}
+
+void APTDemodBaseband::setBasebandSampleRate(int sampleRate)
+{
+ m_channelizer->setBasebandSampleRate(sampleRate);
+ m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
+}
diff --git a/plugins/channelrx/demodapt/aptdemodbaseband.h b/plugins/channelrx/demodapt/aptdemodbaseband.h
new file mode 100644
index 000000000..8acbf26fe
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodbaseband.h
@@ -0,0 +1,94 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMODBASEBAND_H
+#define INCLUDE_APTDEMODBASEBAND_H
+
+#include
+#include
+
+#include "dsp/samplesinkfifo.h"
+#include "util/message.h"
+#include "util/messagequeue.h"
+
+#include "aptdemodsink.h"
+
+class DownChannelizer;
+class APTDemod;
+
+class APTDemodBaseband : public QObject
+{
+ Q_OBJECT
+public:
+ class MsgConfigureAPTDemodBaseband : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const APTDemodSettings& getSettings() const { return m_settings; }
+ bool getForce() const { return m_force; }
+
+ static MsgConfigureAPTDemodBaseband* create(const APTDemodSettings& settings, bool force)
+ {
+ return new MsgConfigureAPTDemodBaseband(settings, force);
+ }
+
+ private:
+ APTDemodSettings m_settings;
+ bool m_force;
+
+ MsgConfigureAPTDemodBaseband(const APTDemodSettings& settings, bool force) :
+ Message(),
+ m_settings(settings),
+ m_force(force)
+ { }
+ };
+
+ APTDemodBaseband(APTDemod *packetDemod);
+ ~APTDemodBaseband();
+ void reset();
+ void startWork();
+ void stopWork();
+ void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
+ MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
+ void getMagSqLevels(double& avg, double& peak, int& nbSamples) {
+ m_sink.getMagSqLevels(avg, peak, nbSamples);
+ }
+ void setMessageQueueToChannel(MessageQueue *messageQueue) { m_sink.setMessageQueueToChannel(messageQueue); }
+ void setBasebandSampleRate(int sampleRate);
+ double getMagSq() const { return m_sink.getMagSq(); }
+ bool isRunning() const { return m_running; }
+
+private:
+ SampleSinkFifo m_sampleFifo;
+ DownChannelizer *m_channelizer;
+ APTDemodSink m_sink;
+ MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
+ APTDemodSettings m_settings;
+ bool m_running;
+ QMutex m_mutex;
+
+ bool handleMessage(const Message& cmd);
+ void calculateOffset(APTDemodSink *sink);
+ void applySettings(const APTDemodSettings& settings, bool force = false);
+
+private slots:
+ void handleInputMessages();
+ void handleData(); //!< Handle data when samples have to be processed
+};
+
+#endif // INCLUDE_APTDEMODBASEBAND_H
diff --git a/plugins/channelrx/demodapt/aptdemodgui.cpp b/plugins/channelrx/demodapt/aptdemodgui.cpp
new file mode 100644
index 000000000..06e724482
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodgui.cpp
@@ -0,0 +1,479 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "aptdemodgui.h"
+#include "util/ax25.h"
+
+#include "device/deviceuiset.h"
+#include "dsp/dspengine.h"
+#include "dsp/dspcommands.h"
+#include "ui_aptdemodgui.h"
+#include "plugin/pluginapi.h"
+#include "util/simpleserializer.h"
+#include "util/db.h"
+#include "util/morse.h"
+#include "util/units.h"
+#include "gui/basicchannelsettingsdialog.h"
+#include "gui/devicestreamselectiondialog.h"
+#include "dsp/dspengine.h"
+#include "gui/crightclickenabler.h"
+#include "channel/channelwebapiutils.h"
+#include "maincore.h"
+
+#include "aptdemod.h"
+#include "aptdemodsink.h"
+#include "aptdemodsettingsdialog.h"
+
+APTDemodGUI* APTDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel)
+{
+ APTDemodGUI* gui = new APTDemodGUI(pluginAPI, deviceUISet, rxChannel);
+ return gui;
+}
+
+void APTDemodGUI::destroy()
+{
+ delete this;
+}
+
+void APTDemodGUI::resetToDefaults()
+{
+ m_settings.resetToDefaults();
+ displaySettings();
+ applySettings(true);
+}
+
+QByteArray APTDemodGUI::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool APTDemodGUI::deserialize(const QByteArray& data)
+{
+ if(m_settings.deserialize(data)) {
+ displaySettings();
+ applySettings(true);
+ return true;
+ } else {
+ resetToDefaults();
+ return false;
+ }
+}
+
+bool APTDemodGUI::handleMessage(const Message& message)
+{
+ if (APTDemod::MsgConfigureAPTDemod::match(message))
+ {
+ qDebug("APTDemodGUI::handleMessage: APTDemod::MsgConfigureAPTDemod");
+ const APTDemod::MsgConfigureAPTDemod& cfg = (APTDemod::MsgConfigureAPTDemod&) message;
+ m_settings = cfg.getSettings();
+ blockApplySettings(true);
+ displaySettings();
+ blockApplySettings(false);
+ return true;
+ }
+ else if (APTDemod::MsgImage::match(message))
+ {
+ const APTDemod::MsgImage& imageMsg = (APTDemod::MsgImage&) message;
+ m_image = imageMsg.getImage();
+ m_pixmap.convertFromImage(m_image);
+ ui->image->setPixmap(m_pixmap);
+ QStringList imageTypes = imageMsg.getImageTypes();
+ if (imageTypes.size() == 0)
+ {
+ ui->channelALabel->setText("Channel A");
+ ui->channelBLabel->setText("Channel B");
+ }
+ else
+ {
+ if (imageTypes[0].isEmpty())
+ ui->channelALabel->setText("Channel A");
+ else
+ ui->channelALabel->setText(imageTypes[0]);
+ if (imageTypes[1].isEmpty())
+ ui->channelBLabel->setText("Channel B");
+ else
+ ui->channelBLabel->setText(imageTypes[1]);
+ }
+ QString satelliteName = imageMsg.getSatelliteName();
+ if (!satelliteName.isEmpty())
+ ui->imageContainer->setWindowTitle("Received image from " + satelliteName);
+ else
+ ui->imageContainer->setWindowTitle("Received image");
+ return true;
+ }
+ else if (DSPSignalNotification::match(message))
+ {
+ DSPSignalNotification& notif = (DSPSignalNotification&) message;
+ m_basebandSampleRate = notif.getSampleRate();
+ return true;
+ }
+
+ return false;
+}
+
+void APTDemodGUI::handleInputMessages()
+{
+ Message* message;
+
+ while ((message = getInputMessageQueue()->pop()) != 0)
+ {
+ if (handleMessage(*message))
+ {
+ delete message;
+ }
+ }
+}
+
+void APTDemodGUI::channelMarkerChangedByCursor()
+{
+ ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
+ m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
+ applySettings();
+}
+
+void APTDemodGUI::channelMarkerHighlightedByCursor()
+{
+ setHighlighted(m_channelMarker.getHighlighted());
+}
+
+void APTDemodGUI::on_deltaFrequency_changed(qint64 value)
+{
+ m_channelMarker.setCenterFrequency(value);
+ m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
+ applySettings();
+}
+
+void APTDemodGUI::on_rfBW_valueChanged(int value)
+{
+ float bw = value * 100.0f;
+ ui->rfBWText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1));
+ m_channelMarker.setBandwidth(bw);
+ m_settings.m_rfBandwidth = bw;
+ applySettings();
+}
+
+void APTDemodGUI::on_fmDev_valueChanged(int value)
+{
+ ui->fmDevText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1));
+ m_settings.m_fmDeviation = value * 100.0;
+ applySettings();
+}
+
+void APTDemodGUI::on_channels_currentIndexChanged(int index)
+{
+ m_settings.m_channels = (APTDemodSettings::ChannelSelection)index;
+ if (m_settings.m_channels == APTDemodSettings::BOTH_CHANNELS)
+ {
+ ui->channelALabel->setVisible(true);
+ ui->channelBLabel->setVisible(true);
+ }
+ else if (m_settings.m_channels == APTDemodSettings::CHANNEL_A)
+ {
+ ui->channelALabel->setVisible(true);
+ ui->channelBLabel->setVisible(false);
+ }
+ else
+ {
+ ui->channelALabel->setVisible(false);
+ ui->channelBLabel->setVisible(true);
+ }
+ applySettings();
+}
+
+void APTDemodGUI::on_cropNoise_clicked(bool checked)
+{
+ m_settings.m_cropNoise = checked;
+ applySettings();
+}
+
+void APTDemodGUI::on_denoise_clicked(bool checked)
+{
+ m_settings.m_denoise = checked;
+ applySettings();
+}
+
+void APTDemodGUI::on_linear_clicked(bool checked)
+{
+ m_settings.m_linearEqualise = checked;
+ applySettings();
+}
+
+void APTDemodGUI::on_histogram_clicked(bool checked)
+{
+ m_settings.m_histogramEqualise = checked;
+ applySettings();
+}
+
+void APTDemodGUI::on_precipitation_clicked(bool checked)
+{
+ m_settings.m_precipitationOverlay = checked;
+ applySettings();
+}
+
+void APTDemodGUI::on_flip_clicked(bool checked)
+{
+ m_settings.m_flip = checked;
+ if (m_settings.m_flip)
+ ui->image->setAlignment(Qt::AlignBottom | Qt::AlignHCenter);
+ else
+ ui->image->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
+ applySettings();
+}
+
+void APTDemodGUI::on_startStop_clicked(bool checked)
+{
+ m_settings.m_decodeEnabled = checked;
+ applySettings();
+}
+
+void APTDemodGUI::on_resetDecoder_clicked()
+{
+ ui->image->setPixmap(QPixmap());
+ ui->imageContainer->setWindowTitle("Received image");
+ // Send message to reset decoder
+ m_aptDemod->getInputMessageQueue()->push(APTDemod::MsgResetDecoder::create());
+}
+
+void APTDemodGUI::on_showSettings_clicked()
+{
+ APTDemodSettingsDialog dialog(&m_settings);
+ if (dialog.exec() == QDialog::Accepted)
+ applySettings();
+}
+
+// Save image to disk
+void APTDemodGUI::on_saveImage_clicked()
+{
+ QFileDialog fileDialog(nullptr, "Select file to save image to", "", "*.png;*.jpg;*.jpeg;*.bmp;*.ppm;*.xbm;*.xpm");
+ fileDialog.setAcceptMode(QFileDialog::AcceptSave);
+ if (fileDialog.exec())
+ {
+ QStringList fileNames = fileDialog.selectedFiles();
+ if (fileNames.size() > 0)
+ {
+ qDebug() << "APT: Saving image to " << fileNames;
+ if (!m_image.save(fileNames[0]))
+ QMessageBox::critical(this, "APT Demodulator", QString("Failed to save image to %1").arg(fileNames[0]));
+ }
+ }
+}
+
+void APTDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
+{
+ (void) widget;
+ (void) rollDown;
+}
+
+void APTDemodGUI::onMenuDialogCalled(const QPoint &p)
+{
+ if (m_contextMenuType == ContextMenuChannelSettings)
+ {
+ BasicChannelSettingsDialog dialog(&m_channelMarker, this);
+ dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
+ dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
+ dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
+ dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
+ dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex);
+ dialog.move(p);
+ dialog.exec();
+
+ m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
+ m_settings.m_title = m_channelMarker.getTitle();
+ m_settings.m_useReverseAPI = dialog.useReverseAPI();
+ m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
+ m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
+ m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
+ m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex();
+
+ setWindowTitle(m_settings.m_title);
+ setTitleColor(m_settings.m_rgbColor);
+
+ applySettings();
+ }
+ else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine))
+ {
+ DeviceStreamSelectionDialog dialog(this);
+ dialog.setNumberOfStreams(m_aptDemod->getNumberOfDeviceStreams());
+ dialog.setStreamIndex(m_settings.m_streamIndex);
+ dialog.move(p);
+ dialog.exec();
+
+ m_settings.m_streamIndex = dialog.getSelectedStreamIndex();
+ m_channelMarker.clearStreamIndexes();
+ m_channelMarker.addStreamIndex(m_settings.m_streamIndex);
+ displayStreamIndex();
+ applySettings();
+ }
+
+ resetContextMenuType();
+}
+
+APTDemodGUI::APTDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) :
+ ChannelGUI(parent),
+ ui(new Ui::APTDemodGUI),
+ m_pluginAPI(pluginAPI),
+ m_deviceUISet(deviceUISet),
+ m_channelMarker(this),
+ m_doApplySettings(true),
+ m_tickCount(0)
+{
+ ui->setupUi(this);
+
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
+
+ m_aptDemod = reinterpret_cast(rxChannel);
+ m_aptDemod->setMessageQueueToGUI(getInputMessageQueue());
+
+ connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
+
+ ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
+ ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
+ ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
+ ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
+
+ m_channelMarker.blockSignals(true);
+ m_channelMarker.setColor(Qt::yellow);
+ m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
+ m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
+ m_channelMarker.setTitle("APT Demodulator");
+ m_channelMarker.blockSignals(false);
+ m_channelMarker.setVisible(true); // activate signal on the last setting only
+
+ setTitleColor(m_channelMarker.getColor());
+ m_settings.setChannelMarker(&m_channelMarker);
+
+ m_deviceUISet->addChannelMarker(&m_channelMarker);
+ m_deviceUISet->addRollupWidget(this);
+
+ connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
+ connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
+ connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
+
+ displaySettings();
+ applySettings(true);
+}
+
+APTDemodGUI::~APTDemodGUI()
+{
+ delete ui;
+}
+
+void APTDemodGUI::blockApplySettings(bool block)
+{
+ m_doApplySettings = !block;
+}
+
+void APTDemodGUI::applySettings(bool force)
+{
+ if (m_doApplySettings)
+ {
+ APTDemod::MsgConfigureAPTDemod* message = APTDemod::MsgConfigureAPTDemod::create( m_settings, force);
+ m_aptDemod->getInputMessageQueue()->push(message);
+ }
+}
+
+void APTDemodGUI::displaySettings()
+{
+ m_channelMarker.blockSignals(true);
+ m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
+ m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
+ m_channelMarker.setTitle(m_settings.m_title);
+ m_channelMarker.blockSignals(false);
+ m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
+
+ setTitleColor(m_settings.m_rgbColor);
+ setWindowTitle(m_channelMarker.getTitle());
+
+ blockApplySettings(true);
+
+ ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
+
+ ui->rfBWText->setText(QString("%1k").arg(m_settings.m_rfBandwidth / 1000.0, 0, 'f', 1));
+ ui->rfBW->setValue(m_settings.m_rfBandwidth / 100.0);
+
+ ui->fmDevText->setText(QString("%1k").arg(m_settings.m_fmDeviation / 1000.0, 0, 'f', 1));
+ ui->fmDev->setValue(m_settings.m_fmDeviation / 100.0);
+
+ ui->startStop->setChecked(m_settings.m_decodeEnabled);
+ ui->cropNoise->setChecked(m_settings.m_cropNoise);
+ ui->denoise->setChecked(m_settings.m_denoise);
+ ui->linear->setChecked(m_settings.m_linearEqualise);
+ ui->histogram->setChecked(m_settings.m_histogramEqualise);
+ ui->precipitation->setChecked(m_settings.m_precipitationOverlay);
+ ui->flip->setChecked(m_settings.m_flip);
+ if (m_settings.m_flip)
+ ui->image->setAlignment(Qt::AlignBottom | Qt::AlignHCenter);
+ else
+ ui->image->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
+ ui->channels->setCurrentIndex((int)m_settings.m_channels);
+
+ displayStreamIndex();
+
+ blockApplySettings(false);
+}
+
+void APTDemodGUI::displayStreamIndex()
+{
+ if (m_deviceUISet->m_deviceMIMOEngine) {
+ setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex));
+ } else {
+ setStreamIndicator("S"); // single channel indicator
+ }
+}
+
+void APTDemodGUI::leaveEvent(QEvent*)
+{
+ m_channelMarker.setHighlighted(false);
+}
+
+void APTDemodGUI::enterEvent(QEvent*)
+{
+ m_channelMarker.setHighlighted(true);
+}
+
+void APTDemodGUI::tick()
+{
+ double magsqAvg, magsqPeak;
+ int nbMagsqSamples;
+ m_aptDemod->getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
+ double powDbAvg = CalcDb::dbPower(magsqAvg);
+ double powDbPeak = CalcDb::dbPower(magsqPeak);
+
+ ui->channelPowerMeter->levelChanged(
+ (100.0f + powDbAvg) / 100.0f,
+ (100.0f + powDbPeak) / 100.0f,
+ nbMagsqSamples);
+
+ if (m_tickCount % 4 == 0) {
+ ui->channelPower->setText(QString::number(powDbAvg, 'f', 1));
+ }
+
+ m_tickCount++;
+}
diff --git a/plugins/channelrx/demodapt/aptdemodgui.h b/plugins/channelrx/demodapt/aptdemodgui.h
new file mode 100644
index 000000000..7c324af48
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodgui.h
@@ -0,0 +1,116 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMODGUI_H
+#define INCLUDE_APTDEMODGUI_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "channel/channelgui.h"
+#include "dsp/channelmarker.h"
+#include "dsp/movingaverage.h"
+#include "util/messagequeue.h"
+#include "aptdemodsettings.h"
+
+class PluginAPI;
+class DeviceUISet;
+class BasebandSampleSink;
+class APTDemod;
+class APTDemodGUI;
+
+namespace Ui {
+ class APTDemodGUI;
+}
+class APTDemodGUI;
+
+class APTDemodGUI : public ChannelGUI {
+ Q_OBJECT
+
+public:
+ static APTDemodGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel);
+ virtual void destroy();
+
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+ virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+
+public slots:
+ void channelMarkerChangedByCursor();
+ void channelMarkerHighlightedByCursor();
+
+private:
+ Ui::APTDemodGUI* ui;
+ PluginAPI* m_pluginAPI;
+ DeviceUISet* m_deviceUISet;
+ ChannelMarker m_channelMarker;
+ APTDemodSettings m_settings;
+ bool m_doApplySettings;
+
+ APTDemod* m_aptDemod;
+ int m_basebandSampleRate;
+ uint32_t m_tickCount;
+ MessageQueue m_inputMessageQueue;
+
+ QImage m_image;
+ QPixmap m_pixmap;
+
+ explicit APTDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
+ virtual ~APTDemodGUI();
+
+ void blockApplySettings(bool block);
+ void applySettings(bool force = false);
+ void displaySettings();
+ void displayStreamIndex();
+ bool handleMessage(const Message& message);
+
+ void leaveEvent(QEvent*);
+ void enterEvent(QEvent*);
+
+private slots:
+ void on_deltaFrequency_changed(qint64 value);
+ void on_rfBW_valueChanged(int index);
+ void on_fmDev_valueChanged(int value);
+ void on_channels_currentIndexChanged(int index);
+ void on_cropNoise_clicked(bool checked=false);
+ void on_denoise_clicked(bool checked=false);
+ void on_linear_clicked(bool checked=false);
+ void on_histogram_clicked(bool checked=false);
+ void on_precipitation_clicked(bool checked=false);
+ void on_flip_clicked(bool checked=false);
+ void on_startStop_clicked(bool checked=false);
+ void on_showSettings_clicked();
+ void on_resetDecoder_clicked();
+ void on_saveImage_clicked();
+ void onWidgetRolled(QWidget* widget, bool rollDown);
+ void onMenuDialogCalled(const QPoint& p);
+ void handleInputMessages();
+ void tick();
+};
+
+#endif // INCLUDE_APTDEMODGUI_H
diff --git a/plugins/channelrx/demodapt/aptdemodgui.ui b/plugins/channelrx/demodapt/aptdemodgui.ui
new file mode 100644
index 000000000..2579d8c26
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodgui.ui
@@ -0,0 +1,723 @@
+
+
+ APTDemodGUI
+
+
+
+ 0
+ 0
+ 451
+ 569
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 352
+ 0
+
+
+
+
+ Liberation Sans
+ 9
+
+
+
+ Qt::StrongFocus
+
+
+ APT Demodulator
+
+
+ APT Demodulator
+
+
+
+
+ 0
+ 0
+ 431
+ 121
+
+
+
+
+ 350
+ 0
+
+
+
+ Settings
+
+
+
+ 3
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+
+
+ 2
+
+
+
+
+
+ 16
+ 0
+
+
+
+ Df
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ Liberation Mono
+ 12
+
+
+
+ PointingHandCursor
+
+
+ Qt::StrongFocus
+
+
+ Demod shift frequency from center in Hz
+
+
+
+
+
+
+ Hz
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+ Channel power
+
+
+ Qt::RightToLeft
+
+
+ 0.0
+
+
+
+
+
+
+ dB
+
+
+
+
+
+
+
+
+
+
+
+
+ dB
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 24
+
+
+
+
+ Liberation Mono
+ 8
+
+
+
+ Level meter (dB) top trace: average, bottom trace: instantaneous peak, tip: peak hold
+
+
+
+
+
+
+
+
+
+
+ BW
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ RF bandwidth
+
+
+ 300
+
+
+ 600
+
+
+ 1
+
+
+ 400
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+ 30
+ 0
+
+
+
+ 40.0k
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+
+
+
+ Dev
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Frequency deviation
+
+
+ 100
+
+
+ 250
+
+
+ 1
+
+
+ 170
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+ 30
+ 0
+
+
+
+ 17.0k
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+
+
+ Start/stop decoding
+
+
+
+
+
+
+ :/play.png
+ :/stop.png:/play.png
+
+
+
+
+
+
+ Show settings dialog
+
+
+
+
+
+
+ :/listing.png:/listing.png
+
+
+
+
+
+
+ Reset decoder (clears current image)
+
+
+
+
+
+
+ :/bin.png:/bin.png
+
+
+
+
+
+
+ Save image to disk
+
+
+
+
+
+
+ :/save.png:/save.png
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ Channels
+
+
+
+
+
+
+
+ 55
+ 0
+
+
+
+ Which channels from the image to display
+
+
+
+ Both
+
+
+
+
+ A
+
+
+
+
+ B
+
+
+
+
+
+
+
+ Crop noise from top and bottom of image
+
+
+ ^
+
+
+
+ :/apt/icons/cropnoise.png:/apt/icons/cropnoise.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ Apply denoise filter to the image
+
+
+ ^
+
+
+
+ :/apt/icons/denoise.png:/apt/icons/denoise.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ Apply linear equalisation to the image
+
+
+ ^
+
+
+
+ :/linear.png:/linear.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ Apply histogram equalisation to the image
+
+
+ ^
+
+
+
+ :/dsb.png:/dsb.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ Overlay precipitation
+
+
+ ^
+
+
+
+ :/apt/icons/precipitation.png:/apt/icons/precipitation.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ Satellite pass direction (flips image)
+
+
+ ^
+
+
+
+ :/arrow_down.png
+ :/arrow_up.png:/arrow_down.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ 0
+ 150
+ 431
+ 381
+
+
+
+
+ 0
+ 0
+
+
+
+ Received Image
+
+
+
+ 2
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+
+
+
+
+ Channel A
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+ Channel B
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 300
+ 350
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+
+
+ RollupWidget
+ QWidget
+ gui/rollupwidget.h
+ 1
+
+
+ ButtonSwitch
+ QToolButton
+ gui/buttonswitch.h
+
+
+ LevelMeterSignalDB
+ QWidget
+ gui/levelmeter.h
+ 1
+
+
+ ValueDialZ
+ QWidget
+ gui/valuedialz.h
+ 1
+
+
+ ScaledImage
+ QLabel
+ gui/scaledimage.h
+
+
+
+ deltaFrequency
+ rfBW
+ fmDev
+ startStop
+ showSettings
+ resetDecoder
+ saveImage
+ channels
+ cropNoise
+ denoise
+ linear
+ histogram
+ precipitation
+ flip
+
+
+
+
+
+
+
diff --git a/plugins/channelrx/demodapt/aptdemodplugin.cpp b/plugins/channelrx/demodapt/aptdemodplugin.cpp
new file mode 100644
index 000000000..cde064db4
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodplugin.cpp
@@ -0,0 +1,92 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include "plugin/pluginapi.h"
+
+#ifndef SERVER_MODE
+#include "aptdemodgui.h"
+#endif
+#include "aptdemod.h"
+#include "aptdemodwebapiadapter.h"
+#include "aptdemodplugin.h"
+
+const PluginDescriptor APTDemodPlugin::m_pluginDescriptor = {
+ APTDemod::m_channelId,
+ QStringLiteral("APT Demodulator"),
+ QStringLiteral("6.5.5"),
+ QStringLiteral("(c) Jon Beniston, M7RCE and Aptdec authors"),
+ QStringLiteral("https://github.com/f4exb/sdrangel"),
+ true,
+ QStringLiteral("https://github.com/f4exb/sdrangel")
+};
+
+APTDemodPlugin::APTDemodPlugin(QObject* parent) :
+ QObject(parent),
+ m_pluginAPI(0)
+{
+}
+
+const PluginDescriptor& APTDemodPlugin::getPluginDescriptor() const
+{
+ return m_pluginDescriptor;
+}
+
+void APTDemodPlugin::initPlugin(PluginAPI* pluginAPI)
+{
+ m_pluginAPI = pluginAPI;
+
+ m_pluginAPI->registerRxChannel(APTDemod::m_channelIdURI, APTDemod::m_channelId, this);
+}
+
+void APTDemodPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const
+{
+ if (bs || cs)
+ {
+ APTDemod *instance = new APTDemod(deviceAPI);
+
+ if (bs) {
+ *bs = instance;
+ }
+
+ if (cs) {
+ *cs = instance;
+ }
+ }
+}
+
+#ifdef SERVER_MODE
+ChannelGUI* APTDemodPlugin::createRxChannelGUI(
+ DeviceUISet *deviceUISet,
+ BasebandSampleSink *rxChannel) const
+{
+ (void) deviceUISet;
+ (void) rxChannel;
+ return 0;
+}
+#else
+ChannelGUI* APTDemodPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const
+{
+ return APTDemodGUI::create(m_pluginAPI, deviceUISet, rxChannel);
+}
+#endif
+
+ChannelWebAPIAdapter* APTDemodPlugin::createChannelWebAPIAdapter() const
+{
+ return new APTDemodWebAPIAdapter();
+}
diff --git a/plugins/channelrx/demodapt/aptdemodplugin.h b/plugins/channelrx/demodapt/aptdemodplugin.h
new file mode 100644
index 000000000..6fce4ea67
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodplugin.h
@@ -0,0 +1,49 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMODPLUGIN_H
+#define INCLUDE_APTDEMODPLUGIN_H
+
+#include
+#include "plugin/plugininterface.h"
+
+class DeviceUISet;
+class BasebandSampleSink;
+
+class APTDemodPlugin : public QObject, PluginInterface {
+ Q_OBJECT
+ Q_INTERFACES(PluginInterface)
+ Q_PLUGIN_METADATA(IID "sdrangel.channel.aptdemod")
+
+public:
+ explicit APTDemodPlugin(QObject* parent = NULL);
+
+ const PluginDescriptor& getPluginDescriptor() const;
+ void initPlugin(PluginAPI* pluginAPI);
+
+ virtual void createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const;
+ virtual ChannelGUI* createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const;
+ virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const;
+
+private:
+ static const PluginDescriptor m_pluginDescriptor;
+
+ PluginAPI* m_pluginAPI;
+};
+
+#endif // INCLUDE_APTDEMODPLUGIN_H
diff --git a/plugins/channelrx/demodapt/aptdemodsettings.cpp b/plugins/channelrx/demodapt/aptdemodsettings.cpp
new file mode 100644
index 000000000..a53e681ce
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodsettings.cpp
@@ -0,0 +1,163 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include "dsp/dspengine.h"
+#include "util/simpleserializer.h"
+#include "settings/serializable.h"
+#include "aptdemodsettings.h"
+
+APTDemodSettings::APTDemodSettings() :
+ m_channelMarker(0)
+{
+ resetToDefaults();
+}
+
+void APTDemodSettings::resetToDefaults()
+{
+ m_inputFrequencyOffset = 0;
+ m_rfBandwidth = 40000.0f;
+ m_fmDeviation = 17000.0f;
+ m_cropNoise = false;
+ m_denoise = true;
+ m_linearEqualise = false;
+ m_histogramEqualise = false;
+ m_precipitationOverlay = false;
+ m_flip = false;
+ m_channels = BOTH_CHANNELS;
+ m_decodeEnabled = true;
+ m_satelliteTrackerControl = true;
+ m_satelliteName = "All";
+ m_autoSave = false;
+ m_autoSavePath = "";
+ m_autoSaveMinScanLines = 200;
+
+ m_rgbColor = QColor(216, 112, 169).rgb();
+ m_title = "APT Demodulator";
+ m_streamIndex = 0;
+ m_useReverseAPI = false;
+ m_reverseAPIAddress = "127.0.0.1";
+ m_reverseAPIPort = 8888;
+ m_reverseAPIDeviceIndex = 0;
+ m_reverseAPIChannelIndex = 0;
+}
+
+QByteArray APTDemodSettings::serialize() const
+{
+ SimpleSerializer s(1);
+ s.writeS32(1, m_inputFrequencyOffset);
+ s.writeS32(2, m_streamIndex);
+ s.writeReal(3, m_rfBandwidth);
+ s.writeReal(4, m_fmDeviation);
+ s.writeBool(5, m_cropNoise);
+ s.writeBool(6, m_denoise);
+ s.writeBool(7, m_linearEqualise);
+ s.writeBool(8, m_histogramEqualise);
+ s.writeBool(9, m_precipitationOverlay);
+ s.writeBool(10, m_flip);
+ s.writeS32(11, (int)m_channels);
+ s.writeBool(12, m_decodeEnabled);
+ s.writeBool(13, m_satelliteTrackerControl);
+ s.writeString(14, m_satelliteName);
+ s.writeBool(15, m_autoSave);
+ s.writeString(16, m_autoSavePath);
+ s.writeS32(17, m_autoSaveMinScanLines);
+
+ if (m_channelMarker) {
+ s.writeBlob(20, m_channelMarker->serialize());
+ }
+
+ s.writeU32(21, m_rgbColor);
+ s.writeString(22, m_title);
+ s.writeBool(23, m_useReverseAPI);
+ s.writeString(24, m_reverseAPIAddress);
+ s.writeU32(25, m_reverseAPIPort);
+ s.writeU32(26, m_reverseAPIDeviceIndex);
+ s.writeU32(27, m_reverseAPIChannelIndex);
+
+ return s.final();
+}
+
+bool APTDemodSettings::deserialize(const QByteArray& data)
+{
+ SimpleDeserializer d(data);
+
+ if(!d.isValid())
+ {
+ resetToDefaults();
+ return false;
+ }
+
+ if(d.getVersion() == 1)
+ {
+ QByteArray bytetmp;
+ uint32_t utmp;
+ QString strtmp;
+
+ d.readS32(1, &m_inputFrequencyOffset, 0);
+ d.readS32(2, &m_streamIndex, 0);
+ d.readReal(3, &m_rfBandwidth, 40000.0f);
+ d.readReal(4, &m_fmDeviation, 17000.0f);
+ d.readBool(5, &m_cropNoise, false);
+ d.readBool(6, &m_denoise, true);
+ d.readBool(7, &m_linearEqualise, false);
+ d.readBool(8, &m_histogramEqualise, false);
+ d.readBool(9, &m_precipitationOverlay, false);
+ d.readBool(10, &m_flip, false);
+ d.readS32(11, (int *)&m_channels, (int)BOTH_CHANNELS);
+ d.readBool(12, &m_decodeEnabled, true);
+ d.readBool(13, &m_satelliteTrackerControl, true);
+ d.readString(14, &m_satelliteName, "All");
+ d.readBool(15, &m_autoSave, false);
+ d.readString(16, &m_autoSavePath, "");
+ d.readS32(17, &m_autoSaveMinScanLines, 200);
+
+ d.readBlob(20, &bytetmp);
+
+ if (m_channelMarker) {
+ m_channelMarker->deserialize(bytetmp);
+ }
+
+ d.readU32(21, &m_rgbColor, QColor(216, 112, 169).rgb());
+ d.readString(22, &m_title, "APT Demodulator");
+ d.readBool(23, &m_useReverseAPI, false);
+ d.readString(24, &m_reverseAPIAddress, "127.0.0.1");
+ d.readU32(25, &utmp, 0);
+
+ if ((utmp > 1023) && (utmp < 65535)) {
+ m_reverseAPIPort = utmp;
+ } else {
+ m_reverseAPIPort = 8888;
+ }
+
+ d.readU32(26, &utmp, 0);
+ m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
+ d.readU32(27, &utmp, 0);
+ m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
+
+ return true;
+ }
+ else
+ {
+ resetToDefaults();
+ return false;
+ }
+}
+
+
diff --git a/plugins/channelrx/demodapt/aptdemodsettings.h b/plugins/channelrx/demodapt/aptdemodsettings.h
new file mode 100644
index 000000000..bcd805562
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodsettings.h
@@ -0,0 +1,64 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMODSETTINGS_H
+#define INCLUDE_APTDEMODSETTINGS_H
+
+#include
+#include
+
+class Serializable;
+
+struct APTDemodSettings
+{
+ qint32 m_inputFrequencyOffset;
+ float m_rfBandwidth;
+ float m_fmDeviation;
+ bool m_cropNoise;
+ bool m_denoise;
+ bool m_linearEqualise;
+ bool m_histogramEqualise;
+ bool m_precipitationOverlay;
+ bool m_flip;
+ enum ChannelSelection {BOTH_CHANNELS, CHANNEL_A, CHANNEL_B} m_channels;
+ bool m_decodeEnabled;
+ bool m_satelliteTrackerControl; //! Whether Sat Tracker can set direction of pass
+ QString m_satelliteName; //!< All, NOAA 15, NOAA 18 or NOAA 19
+ bool m_autoSave;
+ QString m_autoSavePath;
+ int m_autoSaveMinScanLines;
+
+ quint32 m_rgbColor;
+ QString m_title;
+ Serializable *m_channelMarker;
+ QString m_audioDeviceName;
+ int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx).
+ bool m_useReverseAPI;
+ QString m_reverseAPIAddress;
+ uint16_t m_reverseAPIPort;
+ uint16_t m_reverseAPIDeviceIndex;
+ uint16_t m_reverseAPIChannelIndex;
+
+ APTDemodSettings();
+ void resetToDefaults();
+ void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+};
+
+#endif /* INCLUDE_APTDEMODSETTINGS_H */
diff --git a/plugins/channelrx/demodapt/aptdemodsettingsdialog.cpp b/plugins/channelrx/demodapt/aptdemodsettingsdialog.cpp
new file mode 100644
index 000000000..67b160826
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodsettingsdialog.cpp
@@ -0,0 +1,56 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+#include "aptdemodsettingsdialog.h"
+
+APTDemodSettingsDialog::APTDemodSettingsDialog(APTDemodSettings *settings, QWidget* parent) :
+ QDialog(parent),
+ m_settings(settings),
+ ui(new Ui::APTDemodSettingsDialog)
+{
+ ui->setupUi(this);
+ ui->satelliteTrackerControl->setChecked(settings->m_satelliteTrackerControl);
+ ui->satellite->setCurrentText(settings->m_satelliteName);
+ ui->autoSave->setChecked(settings->m_autoSave);
+ ui->autoSavePath->setText(settings->m_autoSavePath);
+ ui->minScanlines->setValue(settings->m_autoSaveMinScanLines);
+}
+
+APTDemodSettingsDialog::~APTDemodSettingsDialog()
+{
+ delete ui;
+}
+
+void APTDemodSettingsDialog::accept()
+{
+ m_settings->m_satelliteTrackerControl = ui->satelliteTrackerControl->isChecked();
+ m_settings->m_satelliteName = ui->satellite->currentText();
+ m_settings->m_autoSave = ui->autoSave->isChecked();
+ m_settings->m_autoSavePath = ui->autoSavePath->text();
+ m_settings->m_autoSaveMinScanLines = ui->minScanlines->value();
+ QDialog::accept();
+}
+
+void APTDemodSettingsDialog::on_autoSavePathBrowse_clicked()
+{
+ QString dir = QFileDialog::getExistingDirectory(this, "Select directory to save images to", "",
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+ ui->autoSavePath->setText(dir);
+}
diff --git a/plugins/channelrx/demodapt/aptdemodsettingsdialog.h b/plugins/channelrx/demodapt/aptdemodsettingsdialog.h
new file mode 100644
index 000000000..f43aaddd1
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodsettingsdialog.h
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMODSETTINGSDIALOG_H
+#define INCLUDE_APTDEMODSETTINGSDIALOG_H
+
+#include "ui_aptdemodsettingsdialog.h"
+#include "aptdemodsettings.h"
+
+class APTDemodSettingsDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit APTDemodSettingsDialog(APTDemodSettings *settings, QWidget* parent = 0);
+ ~APTDemodSettingsDialog();
+
+ APTDemodSettings *m_settings;
+
+private slots:
+ void accept();
+ void on_autoSavePathBrowse_clicked();
+
+private:
+ Ui::APTDemodSettingsDialog* ui;
+};
+
+#endif // INCLUDE_APTDEMODSETTINGSDIALOG_H
diff --git a/plugins/channelrx/demodapt/aptdemodsettingsdialog.ui b/plugins/channelrx/demodapt/aptdemodsettingsdialog.ui
new file mode 100644
index 000000000..4f146269f
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodsettingsdialog.ui
@@ -0,0 +1,205 @@
+
+
+ APTDemodSettingsDialog
+
+
+
+ 0
+ 0
+ 385
+ 212
+
+
+
+
+ Liberation Sans
+ 9
+
+
+
+ APT Demodulator Settings
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Path to save image
+
+
+
+
+
+
+
+
+ Path to save images to
+
+
+
+
+
+
+
+
+
+
+ :/load.png:/load.png
+
+
+
+
+
+
+
+
+ Minimum scanlines
+
+
+
+
+
+
+ Enter the minimum number of scanlines in an image (after cropping) for it to be automatically saved
+
+
+ 1
+
+
+ 30000
+
+
+ 100
+
+
+ 200
+
+
+
+
+
+
+ Satellite
+
+
+
+
+
+
+ Select which satellite this channel will be used for
+
+
+ true
+
+
+
+ All
+
+
+
+
+ NOAA 15
+
+
+
+
+ NOAA 18
+
+
+
+
+ NOAA 19
+
+
+
+
+
+
+
+ Check to enable control by Satellite Tracker feature
+
+
+ Enable Satellite Tracker control
+
+
+
+
+
+
+ Check to automatically save images when acquisition is stopped or LOS
+
+
+ Auto save image
+
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+ satelliteTrackerControl
+ satellite
+ autoSave
+ autoSavePath
+ autoSavePathBrowse
+ minScanlines
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ APTDemodSettingsDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ APTDemodSettingsDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/plugins/channelrx/demodapt/aptdemodsink.cpp b/plugins/channelrx/demodapt/aptdemodsink.cpp
new file mode 100644
index 000000000..38538dc2f
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodsink.cpp
@@ -0,0 +1,205 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include
+
+#include "dsp/dspengine.h"
+#include "dsp/dspengine.h"
+#include "util/db.h"
+#include "util/stepfunctions.h"
+#include "pipes/pipeendpoint.h"
+#include "maincore.h"
+
+#include "aptdemod.h"
+#include "aptdemodsink.h"
+
+APTDemodSink::APTDemodSink(APTDemod *packetDemod) :
+ m_aptDemod(packetDemod),
+ m_channelSampleRate(APTDEMOD_AUDIO_SAMPLE_RATE),
+ m_channelFrequencyOffset(0),
+ m_magsqSum(0.0f),
+ m_magsqPeak(0.0f),
+ m_magsqCount(0),
+ m_messageQueueToChannel(nullptr),
+ m_samples(nullptr)
+{
+ m_magsq = 0.0;
+
+ applySettings(m_settings, true);
+ applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
+
+ m_samplesLength = APTDEMOD_AUDIO_SAMPLE_RATE * APT_MAX_HEIGHT / 2; // APT broadcasts at 2 lines per second
+ m_samples = new float[m_samplesLength];
+
+ resetDecoder();
+}
+
+void APTDemodSink::resetDecoder()
+{
+ m_sampleCount = 0;
+ m_writeIdx = 0;
+ m_readIdx = 0;
+
+ apt_init(APTDEMOD_AUDIO_SAMPLE_RATE);
+
+ m_row = 0;
+ m_zenith = 0;
+}
+
+APTDemodSink::~APTDemodSink()
+{
+ delete m_samples;
+}
+
+// callback from APT library to get audio samples
+static int getsamples(void *context, float *samples, int count)
+{
+ APTDemodSink *sink = (APTDemodSink *)context;
+ return sink->getSamples(samples, count);
+}
+
+int APTDemodSink::getSamples(float *samples, int count)
+{
+ for (int i = 0; i < count; i++)
+ {
+ if ((m_sampleCount > 0) && (m_readIdx < m_samplesLength))
+ {
+ *samples++ = m_samples[m_readIdx++];
+ m_sampleCount--;
+ }
+ else
+ return i;
+ }
+
+ return count;
+}
+
+void APTDemodSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
+{
+ Complex ci;
+
+ for (SampleVector::const_iterator it = begin; it != end; ++it)
+ {
+ Complex c(it->real(), it->imag());
+ c *= m_nco.nextIQ();
+
+ if (m_interpolatorDistance < 1.0f) // interpolate
+ {
+ while (!m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
+ {
+ processOneSample(ci);
+ m_interpolatorDistanceRemain += m_interpolatorDistance;
+ }
+ }
+ else // decimate
+ {
+ if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
+ {
+ processOneSample(ci);
+ m_interpolatorDistanceRemain += m_interpolatorDistance;
+ }
+ }
+ }
+
+ // Have we enough samples to decode one line?
+ // 2 lines per second
+ if (m_sampleCount >= APTDEMOD_AUDIO_SAMPLE_RATE)
+ {
+ float pixels[APT_PROW_WIDTH];
+ apt_getpixelrow(pixels, m_row, &m_zenith, m_row == 0, getsamples, this);
+ getMessageQueueToChannel()->push(APTDemod::MsgPixels::create(pixels, m_zenith));
+ m_row++;
+ }
+}
+
+
+void APTDemodSink::processOneSample(Complex &ci)
+{
+ Complex ca;
+
+ // FM demodulation
+ double magsqRaw;
+ Real deviation;
+ Real fmDemod = m_phaseDiscri.phaseDiscriminatorDelta(ci, magsqRaw, deviation);
+
+ // Add to sample buffer, if there's space and decoding is enabled
+ if ((m_writeIdx < m_samplesLength) && m_settings.m_decodeEnabled)
+ {
+ m_samples[m_writeIdx++] = fmDemod;
+ m_sampleCount++;
+ }
+
+ // Calculate average and peak levels for level meter
+ Real magsq = magsqRaw / (SDR_RX_SCALED*SDR_RX_SCALED);
+ m_movingAverage(magsq);
+ m_magsq = m_movingAverage.asDouble();
+ m_magsqSum += magsq;
+ if (magsq > m_magsqPeak)
+ {
+ m_magsqPeak = magsq;
+ }
+ m_magsqCount++;
+}
+
+void APTDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
+{
+ qDebug() << "APTDemodSink::applyChannelSettings:"
+ << " channelSampleRate: " << channelSampleRate
+ << " channelFrequencyOffset: " << channelFrequencyOffset;
+
+ if ((m_channelFrequencyOffset != channelFrequencyOffset) ||
+ (m_channelSampleRate != channelSampleRate) || force)
+ {
+ m_nco.setFreq(-channelFrequencyOffset, channelSampleRate);
+ }
+
+ if ((m_channelSampleRate != channelSampleRate) || force)
+ {
+ m_interpolator.create(16, channelSampleRate, m_settings.m_rfBandwidth, 2.2);
+ m_interpolatorDistance = (Real) channelSampleRate / (Real) APTDEMOD_AUDIO_SAMPLE_RATE;
+ m_interpolatorDistanceRemain = m_interpolatorDistance;
+ }
+
+ m_channelSampleRate = channelSampleRate;
+ m_channelFrequencyOffset = channelFrequencyOffset;
+}
+
+void APTDemodSink::applySettings(const APTDemodSettings& settings, bool force)
+{
+ qDebug() << "APTDemodSink::applySettings:"
+ << " m_rfBandwidth: " << settings.m_rfBandwidth
+ << " m_fmDeviation: " << settings.m_fmDeviation
+ << " m_decodeEnabled: " << settings.m_decodeEnabled
+ << " force: " << force;
+
+ if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
+ {
+ m_interpolator.create(16, m_channelSampleRate, settings.m_rfBandwidth, 2.2);
+ m_interpolatorDistance = (Real) m_channelSampleRate / (Real) APTDEMOD_AUDIO_SAMPLE_RATE;
+ m_interpolatorDistanceRemain = m_interpolatorDistance;
+ }
+
+ if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
+ {
+ m_phaseDiscri.setFMScaling(APTDEMOD_AUDIO_SAMPLE_RATE / (2.0f * settings.m_fmDeviation));
+ }
+
+ m_settings = settings;
+}
diff --git a/plugins/channelrx/demodapt/aptdemodsink.h b/plugins/channelrx/demodapt/aptdemodsink.h
new file mode 100644
index 000000000..9a8a14284
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodsink.h
@@ -0,0 +1,126 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 Edouard Griffiths, F4EXB //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMODSINK_H
+#define INCLUDE_APTDEMODSINK_H
+
+#include "dsp/channelsamplesink.h"
+#include "dsp/phasediscri.h"
+#include "dsp/nco.h"
+#include "dsp/interpolator.h"
+#include "dsp/firfilter.h"
+#include "util/movingaverage.h"
+#include "util/doublebufferfifo.h"
+#include "util/messagequeue.h"
+
+#include "aptdemodsettings.h"
+#include
+
+#include
+#include
+#include
+
+// FIXME: Use lower sample rate for better SNR?
+// Do we want an audio filter? Subcarrier at 2800Hz. Does libaptdec have one?
+#define APTDEMOD_AUDIO_SAMPLE_RATE 48000
+// Lines are 2 per second -> 4160 words per second
+
+class APTDemod;
+
+class APTDemodSink : public ChannelSampleSink {
+public:
+ APTDemodSink(APTDemod *packetDemod);
+ ~APTDemodSink();
+
+ virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
+
+ void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
+ void applySettings(const APTDemodSettings& settings, bool force = false);
+ void setMessageQueueToChannel(MessageQueue *messageQueue) { m_messageQueueToChannel = messageQueue; }
+
+ double getMagSq() const { return m_magsq; }
+
+ void getMagSqLevels(double& avg, double& peak, int& nbSamples)
+ {
+ if (m_magsqCount > 0)
+ {
+ m_magsq = m_magsqSum / m_magsqCount;
+ m_magSqLevelStore.m_magsq = m_magsq;
+ m_magSqLevelStore.m_magsqPeak = m_magsqPeak;
+ }
+
+ avg = m_magSqLevelStore.m_magsq;
+ peak = m_magSqLevelStore.m_magsqPeak;
+ nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
+
+ m_magsqSum = 0.0f;
+ m_magsqPeak = 0.0f;
+ m_magsqCount = 0;
+ }
+
+ int getSamples(float *samples, int count);
+ void resetDecoder();
+
+private:
+ struct MagSqLevelsStore
+ {
+ MagSqLevelsStore() :
+ m_magsq(1e-12),
+ m_magsqPeak(1e-12)
+ {}
+ double m_magsq;
+ double m_magsqPeak;
+ };
+
+ APTDemod *m_aptDemod;
+ APTDemodSettings m_settings;
+ int m_channelSampleRate;
+ int m_channelFrequencyOffset;
+
+ NCO m_nco;
+ Interpolator m_interpolator;
+ Real m_interpolatorDistance;
+ Real m_interpolatorDistanceRemain;
+
+ double m_magsq;
+ double m_magsqSum;
+ double m_magsqPeak;
+ int m_magsqCount;
+ MagSqLevelsStore m_magSqLevelStore;
+
+ MessageQueue *m_messageQueueToChannel;
+
+ MovingAverageUtil m_movingAverage;
+
+ PhaseDiscriminators m_phaseDiscri;
+
+ // Audio buffer - should probably use a FIFO
+ float *m_samples;
+ int m_sampleCount;
+ int m_samplesLength;
+ int m_readIdx;
+ int m_writeIdx;
+
+ int m_row; // Row of image currently being received
+ int m_zenith; // Row number of Zenith
+
+ void processOneSample(Complex &ci);
+ MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; }
+};
+
+#endif // INCLUDE_APTDEMODSINK_H
diff --git a/plugins/channelrx/demodapt/aptdemodwebapiadapter.cpp b/plugins/channelrx/demodapt/aptdemodwebapiadapter.cpp
new file mode 100644
index 000000000..b6cc87b0a
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodwebapiadapter.cpp
@@ -0,0 +1,52 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "SWGChannelSettings.h"
+#include "aptdemod.h"
+#include "aptdemodwebapiadapter.h"
+
+APTDemodWebAPIAdapter::APTDemodWebAPIAdapter()
+{}
+
+APTDemodWebAPIAdapter::~APTDemodWebAPIAdapter()
+{}
+
+int APTDemodWebAPIAdapter::webapiSettingsGet(
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage)
+{
+ (void) errorMessage;
+ response.setAptDemodSettings(new SWGSDRangel::SWGAPTDemodSettings());
+ response.getAptDemodSettings()->init();
+ APTDemod::webapiFormatChannelSettings(response, m_settings);
+
+ return 200;
+}
+
+int APTDemodWebAPIAdapter::webapiSettingsPutPatch(
+ bool force,
+ const QStringList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage)
+{
+ (void) force;
+ (void) errorMessage;
+ APTDemod::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response);
+
+ return 200;
+}
diff --git a/plugins/channelrx/demodapt/aptdemodwebapiadapter.h b/plugins/channelrx/demodapt/aptdemodwebapiadapter.h
new file mode 100644
index 000000000..32027f238
--- /dev/null
+++ b/plugins/channelrx/demodapt/aptdemodwebapiadapter.h
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
+// Copyright (C) 2020 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_APTDEMOD_WEBAPIADAPTER_H
+#define INCLUDE_APTDEMOD_WEBAPIADAPTER_H
+
+#include "channel/channelwebapiadapter.h"
+#include "aptdemodsettings.h"
+
+/**
+ * Standalone API adapter only for the settings
+ */
+class APTDemodWebAPIAdapter : public ChannelWebAPIAdapter {
+public:
+ APTDemodWebAPIAdapter();
+ virtual ~APTDemodWebAPIAdapter();
+
+ virtual QByteArray serialize() const { return m_settings.serialize(); }
+ virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
+
+ virtual int webapiSettingsGet(
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage);
+
+ virtual int webapiSettingsPutPatch(
+ bool force,
+ const QStringList& channelSettingsKeys,
+ SWGSDRangel::SWGChannelSettings& response,
+ QString& errorMessage);
+
+private:
+ APTDemodSettings m_settings;
+};
+
+#endif // INCLUDE_APTDEMOD_WEBAPIADAPTER_H
diff --git a/plugins/channelrx/demodapt/icons.qrc b/plugins/channelrx/demodapt/icons.qrc
new file mode 100644
index 000000000..0806ccca5
--- /dev/null
+++ b/plugins/channelrx/demodapt/icons.qrc
@@ -0,0 +1,7 @@
+
+
+ icons/cropnoise.png
+ icons/denoise.png
+ icons/precipitation.png
+
+
diff --git a/plugins/channelrx/demodapt/icons/cropnoise.png b/plugins/channelrx/demodapt/icons/cropnoise.png
new file mode 100644
index 000000000..e6d4f6944
Binary files /dev/null and b/plugins/channelrx/demodapt/icons/cropnoise.png differ
diff --git a/plugins/channelrx/demodapt/icons/denoise.png b/plugins/channelrx/demodapt/icons/denoise.png
new file mode 100644
index 000000000..4084374ad
Binary files /dev/null and b/plugins/channelrx/demodapt/icons/denoise.png differ
diff --git a/plugins/channelrx/demodapt/icons/precipitation.png b/plugins/channelrx/demodapt/icons/precipitation.png
new file mode 100644
index 000000000..0f2a8a6a0
Binary files /dev/null and b/plugins/channelrx/demodapt/icons/precipitation.png differ
diff --git a/plugins/channelrx/demodapt/readme.md b/plugins/channelrx/demodapt/readme.md
new file mode 100644
index 000000000..a81ec7b7a
--- /dev/null
+++ b/plugins/channelrx/demodapt/readme.md
@@ -0,0 +1,108 @@
+
APT Demodulator Plugin
+
+
Introduction
+
+This plugin can be used to demodulate APT (Automatic Picture Transmission) signals transmitted by NOAA weather satellites. These images are at a 4km/pixel resolution in either the visible, near-IR, mid-IR or thermal-IR bands.
+
+
+
+* NOAA 15 transmits on 137.620 MHz.
+* NOAA 18 transmits on 137.912 MHz.
+* NOAA 19 transmits on 137.100 MHz.
+
+
1: Frequency shift from center frequency of reception
+
+Use the wheels to adjust the frequency shift in Hz from the center frequency of reception. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2.
+
+
2: Channel power
+
+Average total power in dB relative to a +/- 1.0 amplitude signal received in the pass band.
+
+
3: Level meter in dB
+
+ - top bar (green): average value
+ - bottom bar (blue green): instantaneous peak value
+ - tip vertical bar (bright green): peak hold value
+
+
4: RF Bandwidth
+
+This specifies the bandwidth of a LPF that is applied to the input signal to limit the RF bandwidth. APT signals are nominally 34kHz wide, however, this defaults to 40kHz to allow for some Doppler shift.
+
+
5: Frequency deviation
+
+Adjusts the expected frequency deviation in 0.1 kHz steps from 10 to 25 kHz. The typical value for APT is 17 kHz.
+
+
6: Start/stop decoding
+
+Starts or stops decoding. A maximum of 3000 scanlines can be decoded, after which, the Reset Decoder (7) button needs to be pressed, to start a new image.
+
+
7: Show settings dialog
+
+When clicked, shows additional APT Demodulator settings.
+
+
+
+This includes:
+
+ - Whether the APT demodulator can be controlled by the Satellite Tracker feature. When checked, the image decoder will be enabled and reset on AOS and the satellite pass direction will be used to control image rotation. The decoder will be stopped on LOS.
+ - Which satellites the APT demodulator will respond to AOS and LOS indications from the Satellite Tracker. This can be used to simulataneously decode images from multiple satellites, by having multiple instances of the APT Demodulator and setting a unique satellite name for each demodulator.
+ - Whether to automatically save the image on LOS.
+ - Path to save automatically saved images in.
+ - The minimum number of scanlines required to be in an image, after noise cropping, for it to be automatically saved.
+
+
8: Reset decoder
+
+Clears the current image and restarts the decoder. The decoder must be reset between passes of different satellites.
+
+
9: Save image to disk
+
+Saves the current image to disk. Images can be saved in PNG, JPEG, BMP, PPM, XBM or XPM formats.
+
+
10: Channel selection
+
+Selects whether:
+
+ - both channels are displayed
+ - only channel A is displayed
+ - only channel B is displayed
+
+
11: Crop noise
+
+When checked, noise is cropped from the top and bottom of the image. This is noise that is typically the result of the satellite being at a low elevation.
+
+
12: Apply denoise filter
+
+When checked, a denoise filter is applied to the received image.
+
+
13: Apply linear equalisation
+
+When checked, linear equalisation is performed, which can enhance the contrast. The equalisation is performed separately on each channel.
+
+
14: Apply histogram equalisation
+
+When checked, histogram equalisation is performed, which can enhance the contrast. The equalisation is performed separately on each channel.
+
+
15: Overlay precipitation
+
+When checked, precipitation is detected from the IR channel and overlayed on both channels using a colour palette.
+
+This option will not work if linear or histogram equalisation has been applied.
+
+
16: Pass direction
+
+The pass direction check button should be set to match the direction of the satellite pass.
+i.e. select down arrow for satellite passing from the North to the South and the up arrow for the satellite passing from the South to the North.
+This will ensure the image has the Northern latitudes at the top of the image.
+This can be set automatically by the Satellite Tracker feature.
+
+
Attribution
+
+This plugin uses libapt, part of Aptdec by Thierry Leconte and Xerbo, to perform image decoding and processing: https://github.com/Xerbo/aptdec
+
+Icons are by Freepik from Flaticon https://www.flaticon.com/
+
+Icons are by Hare Krishna from the Noun Project Noun Project: https://thenounproject.com/
diff --git a/plugins/channelrx/demodpacket/packetdemod.cpp b/plugins/channelrx/demodpacket/packetdemod.cpp
index 068d9fb88..2df2698af 100644
--- a/plugins/channelrx/demodpacket/packetdemod.cpp
+++ b/plugins/channelrx/demodpacket/packetdemod.cpp
@@ -42,7 +42,7 @@
MESSAGE_CLASS_DEFINITION(PacketDemod::MsgConfigurePacketDemod, Message)
-const char * const PacketDemod::m_channelIdURI = "sdrangel.channelrx.packetdemod";
+const char * const PacketDemod::m_channelIdURI = "sdrangel.channel.packetdemod";
const char * const PacketDemod::m_channelId = "PacketDemod";
PacketDemod::PacketDemod(DeviceAPI *deviceAPI) :
diff --git a/plugins/channelrx/demodpacket/packetdemodsettings.cpp b/plugins/channelrx/demodpacket/packetdemodsettings.cpp
index c7652d3a0..b771202ea 100644
--- a/plugins/channelrx/demodpacket/packetdemodsettings.cpp
+++ b/plugins/channelrx/demodpacket/packetdemodsettings.cpp
@@ -39,7 +39,7 @@ void PacketDemodSettings::resetToDefaults()
m_filterTo = "";
m_filterPID = "";
- m_rgbColor = QColor(255, 255, 0).rgb();
+ m_rgbColor = QColor(0, 105, 2).rgb();
m_title = "Packet Demodulator";
m_streamIndex = 0;
m_useReverseAPI = false;
@@ -76,6 +76,9 @@ QByteArray PacketDemodSettings::serialize() const
s.writeU32(17, m_reverseAPIDeviceIndex);
s.writeU32(18, m_reverseAPIChannelIndex);
+ s.writeFloat(20, m_rfBandwidth);
+ s.writeFloat(21, m_fmDeviation);
+
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
s.writeS32(100 + i, m_columnIndexes[i]);
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
@@ -111,7 +114,7 @@ bool PacketDemodSettings::deserialize(const QByteArray& data)
m_channelMarker->deserialize(bytetmp);
}
- d.readU32(7, &m_rgbColor);
+ d.readU32(7, &m_rgbColor, QColor(0, 105, 2).rgb());
d.readString(9, &m_title, "Packet Demodulator");
d.readBool(14, &m_useReverseAPI, false);
d.readString(15, &m_reverseAPIAddress, "127.0.0.1");
@@ -128,6 +131,9 @@ bool PacketDemodSettings::deserialize(const QByteArray& data)
d.readU32(18, &utmp, 0);
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
+ d.readFloat(20, &m_rfBandwidth, 12500.0f);
+ d.readFloat(21, &m_fmDeviation, 2500.0f);
+
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
d.readS32(100 + i, &m_columnIndexes[i], i);
for (int i = 0; i < PACKETDEMOD_COLUMNS; i++)
diff --git a/plugins/channelrx/demodvor/vordemodsettings.cpp b/plugins/channelrx/demodvor/vordemodsettings.cpp
index e0c7e35ab..a33311496 100644
--- a/plugins/channelrx/demodvor/vordemodsettings.cpp
+++ b/plugins/channelrx/demodvor/vordemodsettings.cpp
@@ -34,7 +34,7 @@ void VORDemodSettings::resetToDefaults()
m_squelch = -60.0;
m_volume = 2.0;
m_audioMute = false;
- m_rgbColor = QColor(255, 255, 0).rgb();
+ m_rgbColor = QColor(255, 255, 102).rgb();
m_title = "VOR Demodulator";
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
m_streamIndex = 0;
@@ -117,7 +117,7 @@ bool VORDemodSettings::deserialize(const QByteArray& data)
m_channelMarker->deserialize(bytetmp);
}
- d.readU32(7, &m_rgbColor);
+ d.readU32(7, &m_rgbColor, QColor(255, 255, 102).rgb());
d.readString(9, &m_title, "VOR Demodulator");
d.readString(11, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
d.readBool(14, &m_useReverseAPI, false);
diff --git a/plugins/feature/CMakeLists.txt b/plugins/feature/CMakeLists.txt
index 3bd131099..df3ba354d 100644
--- a/plugins/feature/CMakeLists.txt
+++ b/plugins/feature/CMakeLists.txt
@@ -16,4 +16,7 @@ add_subdirectory(aprs)
add_subdirectory(demodanalyzer)
add_subdirectory(rigctlserver)
add_subdirectory(simpleptt)
+if (SGP4_FOUND)
+ add_subdirectory(satellitetracker)
+endif()
add_subdirectory(startracker)
diff --git a/plugins/feature/aprs/CMakeLists.txt b/plugins/feature/aprs/CMakeLists.txt
index 30d66a3ed..65cefdf7c 100644
--- a/plugins/feature/aprs/CMakeLists.txt
+++ b/plugins/feature/aprs/CMakeLists.txt
@@ -60,8 +60,3 @@ target_link_libraries(${TARGET_NAME}
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
-if(WIN32)
- # Run deployqt for Charts etc
- include(DeployQt)
- windeployqt(${TARGET_NAME} ${SDRANGEL_BINARY_BIN_DIR} ${PROJECT_SOURCE_DIR}/aprs)
-endif()
diff --git a/plugins/feature/aprs/aprsgui.cpp b/plugins/feature/aprs/aprsgui.cpp
index bd8c78fc9..e44153bee 100644
--- a/plugins/feature/aprs/aprsgui.cpp
+++ b/plugins/feature/aprs/aprsgui.cpp
@@ -519,18 +519,24 @@ APRSGUI::APRSGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feat
ui->weatherChart->setRenderHint(QPainter::Antialiasing);
m_weatherChart.addAxis(&m_weatherChartXAxis, Qt::AlignBottom);
m_weatherChart.addAxis(&m_weatherChartYAxis, Qt::AlignLeft);
+ m_weatherChart.layout()->setContentsMargins(0, 0, 0, 0);
+ m_weatherChart.setMargins(QMargins(1, 1, 1, 1));
m_telemetryChart.legend()->hide();
ui->telemetryChart->setChart(&m_telemetryChart);
ui->telemetryChart->setRenderHint(QPainter::Antialiasing);
m_telemetryChart.addAxis(&m_telemetryChartXAxis, Qt::AlignBottom);
m_telemetryChart.addAxis(&m_telemetryChartYAxis, Qt::AlignLeft);
+ m_telemetryChart.layout()->setContentsMargins(0, 0, 0, 0);
+ m_telemetryChart.setMargins(QMargins(1, 1, 1, 1));
m_motionChart.legend()->hide();
ui->motionChart->setChart(&m_motionChart);
ui->motionChart->setRenderHint(QPainter::Antialiasing);
m_motionChart.addAxis(&m_motionChartXAxis, Qt::AlignBottom);
m_motionChart.addAxis(&m_motionChartYAxis, Qt::AlignLeft);
+ m_motionChart.layout()->setContentsMargins(0, 0, 0, 0);
+ m_motionChart.setMargins(QMargins(1, 1, 1, 1));
displaySettings();
applySettings(true);
diff --git a/plugins/feature/aprs/aprssettings.cpp b/plugins/feature/aprs/aprssettings.cpp
index 6219d8613..368beca30 100644
--- a/plugins/feature/aprs/aprssettings.cpp
+++ b/plugins/feature/aprs/aprssettings.cpp
@@ -28,7 +28,7 @@ const QStringList APRSSettings::m_pipeTypes = {
};
const QStringList APRSSettings::m_pipeURIs = {
- QStringLiteral("sdrangel.channelrx.packetdemod"),
+ QStringLiteral("sdrangel.channel.packetdemod"),
};
APRSSettings::APRSSettings()
diff --git a/plugins/feature/gs232controller/gs232controller.cpp b/plugins/feature/gs232controller/gs232controller.cpp
index 0ea28d684..6e83a841e 100644
--- a/plugins/feature/gs232controller/gs232controller.cpp
+++ b/plugins/feature/gs232controller/gs232controller.cpp
@@ -210,6 +210,12 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo
qDebug() << "GS232Controller::applySettings:"
<< " m_azimuth: " << settings.m_azimuth
<< " m_elevation: " << settings.m_elevation
+ << " m_azimuthOffset: " << settings.m_azimuthOffset
+ << " m_elevationOffset: " << settings.m_elevationOffset
+ << " m_azimuthMin: " << settings.m_azimuthMin
+ << " m_azimuthMax: " << settings.m_azimuthMax
+ << " m_elevationMin: " << settings.m_elevationMin
+ << " m_elevationMax: " << settings.m_elevationMax
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " m_track: " << settings.m_track
@@ -259,6 +265,15 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, boo
if ((m_settings.m_elevationOffset != settings.m_elevationOffset) || force) {
reverseAPIKeys.append("elevationOffset");
}
+ if ((m_settings.m_azimuthMin != settings.m_azimuthMin) || force) {
+ reverseAPIKeys.append("azimuthMin");
+ }
+ if ((m_settings.m_azimuthMax != settings.m_azimuthMax) || force) {
+ reverseAPIKeys.append("azimuthMax");
+ }
+ if ((m_settings.m_elevationMin != settings.m_elevationMin) || force) {
+ reverseAPIKeys.append("elevationMin");
+ }
if ((m_settings.m_title != settings.m_title) || force) {
reverseAPIKeys.append("title");
}
@@ -341,6 +356,10 @@ void GS232Controller::webapiFormatFeatureSettings(
response.getGs232ControllerSettings()->setTrack(settings.m_track);
response.getGs232ControllerSettings()->setAzimuthOffset(settings.m_azimuthOffset);
response.getGs232ControllerSettings()->setElevationOffset(settings.m_elevationOffset);
+ response.getGs232ControllerSettings()->setAzimuthMin(settings.m_azimuthMin);
+ response.getGs232ControllerSettings()->setAzimuthMax(settings.m_azimuthMax);
+ response.getGs232ControllerSettings()->setElevationMin(settings.m_elevationMin);
+ response.getGs232ControllerSettings()->setElevationMax(settings.m_elevationMax);
if (response.getGs232ControllerSettings()->getTitle()) {
*response.getGs232ControllerSettings()->getTitle() = settings.m_title;
@@ -389,6 +408,18 @@ void GS232Controller::webapiUpdateFeatureSettings(
if (featureSettingsKeys.contains("elevationOffset")) {
settings.m_elevationOffset = response.getGs232ControllerSettings()->getElevationOffset();
}
+ if (featureSettingsKeys.contains("azimuthMin")) {
+ settings.m_azimuthMin = response.getGs232ControllerSettings()->getAzimuthMin();
+ }
+ if (featureSettingsKeys.contains("azimuthMax")) {
+ settings.m_azimuthMax = response.getGs232ControllerSettings()->getAzimuthMax();
+ }
+ if (featureSettingsKeys.contains("elevationMin")) {
+ settings.m_elevationMin = response.getGs232ControllerSettings()->getElevationMin();
+ }
+ if (featureSettingsKeys.contains("elevationMax")) {
+ settings.m_elevationMax = response.getGs232ControllerSettings()->getElevationMax();
+ }
if (featureSettingsKeys.contains("title")) {
settings.m_title = *response.getGs232ControllerSettings()->getTitle();
}
@@ -441,6 +472,18 @@ void GS232Controller::webapiReverseSendSettings(QList& featureSettingsK
if (featureSettingsKeys.contains("elevationOffset") || force) {
swgGS232ControllerSettings->setElevationOffset(settings.m_elevationOffset);
}
+ if (featureSettingsKeys.contains("azimuthMin") || force) {
+ swgGS232ControllerSettings->setAzimuthMin(settings.m_azimuthMin);
+ }
+ if (featureSettingsKeys.contains("azimuthMax") || force) {
+ swgGS232ControllerSettings->setAzimuthMax(settings.m_azimuthMax);
+ }
+ if (featureSettingsKeys.contains("elevationMin") || force) {
+ swgGS232ControllerSettings->setElevationMin(settings.m_elevationMin);
+ }
+ if (featureSettingsKeys.contains("elevationMax") || force) {
+ swgGS232ControllerSettings->setElevationMax(settings.m_elevationMax);
+ }
if (featureSettingsKeys.contains("title") || force) {
swgGS232ControllerSettings->setTitle(new QString(settings.m_title));
}
diff --git a/plugins/feature/gs232controller/gs232controllergui.cpp b/plugins/feature/gs232controller/gs232controllergui.cpp
index 9ed62c6f0..f53445912 100644
--- a/plugins/feature/gs232controller/gs232controllergui.cpp
+++ b/plugins/feature/gs232controller/gs232controllergui.cpp
@@ -182,6 +182,10 @@ void GS232ControllerGUI::displaySettings()
ui->targets->setCurrentIndex(ui->targets->findText(m_settings.m_target));
ui->azimuthOffset->setValue(m_settings.m_azimuthOffset);
ui->elevationOffset->setValue(m_settings.m_elevationOffset);
+ ui->azimuthMin->setValue(m_settings.m_azimuthMin);
+ ui->azimuthMax->setValue(m_settings.m_azimuthMax);
+ ui->elevationMin->setValue(m_settings.m_elevationMin);
+ ui->elevationMax->setValue(m_settings.m_elevationMax);
blockApplySettings(false);
}
@@ -317,6 +321,30 @@ void GS232ControllerGUI::on_elevationOffset_valueChanged(int value)
applySettings();
}
+void GS232ControllerGUI::on_azimuthMin_valueChanged(int value)
+{
+ m_settings.m_azimuthMin = value;
+ applySettings();
+}
+
+void GS232ControllerGUI::on_azimuthMax_valueChanged(int value)
+{
+ m_settings.m_azimuthMax = value;
+ applySettings();
+}
+
+void GS232ControllerGUI::on_elevationMin_valueChanged(int value)
+{
+ m_settings.m_elevationMin = value;
+ applySettings();
+}
+
+void GS232ControllerGUI::on_elevationMax_valueChanged(int value)
+{
+ m_settings.m_elevationMax = value;
+ applySettings();
+}
+
void GS232ControllerGUI::on_track_stateChanged(int state)
{
m_settings.m_track = state == Qt::Checked;
diff --git a/plugins/feature/gs232controller/gs232controllergui.h b/plugins/feature/gs232controller/gs232controllergui.h
index b43356a3d..8d46300e2 100644
--- a/plugins/feature/gs232controller/gs232controllergui.h
+++ b/plugins/feature/gs232controller/gs232controllergui.h
@@ -84,6 +84,10 @@ private slots:
void on_targets_currentTextChanged(const QString& text);
void on_azimuthOffset_valueChanged(int value);
void on_elevationOffset_valueChanged(int value);
+ void on_azimuthMin_valueChanged(int value);
+ void on_azimuthMax_valueChanged(int value);
+ void on_elevationMin_valueChanged(int value);
+ void on_elevationMax_valueChanged(int value);
void updateStatus();
};
diff --git a/plugins/feature/gs232controller/gs232controllergui.ui b/plugins/feature/gs232controller/gs232controllergui.ui
index 71b594c3c..0feb96f4d 100644
--- a/plugins/feature/gs232controller/gs232controllergui.ui
+++ b/plugins/feature/gs232controller/gs232controllergui.ui
@@ -6,8 +6,8 @@
00
- 320
- 175
+ 350
+ 223
@@ -42,8 +42,8 @@
1010
- 301
- 161
+ 331
+ 191
@@ -248,45 +248,50 @@
-
-
-
-
- Serial Port
-
-
-
-
-
-
- Name of serial port to use to connect to the GS-232 controller
-
-
- true
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
+
+ Baud rate
-
+
+
+
+ 180
+
+
+
+
+
+
+ Elevation min
+
+
+
+
+
+
+ Azimuth min
+
+
+
+
+
+
+ Elevation max
+
+
+
+
+
+
+ 180
+
+
+
+ Serial port baud rate for the GS-232 controller
@@ -336,18 +341,52 @@
-
-
-
-
-
+
+
+
+ 450
+
+
+
+
+
+
+ 450
+
+
+
+
+
+
+ Name of serial port to use to connect to the GS-232 controller
+
+
+ true
+
+
+
+
+
+
+ Serial Port
+
+
+
+
+
+
+ Azimuth max
+
+
+
+ Azimuth offset
-
+ Specify an offset angel in degrees that will be added to the target azimuth to correct for misalignment
@@ -360,14 +399,14 @@
-
+ Elevation offset
-
+ Specify an offset angle in degrees that will be added to the target elevation to correct for misalignment
@@ -412,6 +451,10 @@
baudRateazimuthOffsetelevationOffset
+ azimuthMin
+ azimuthMax
+ elevationMin
+ elevationMax
diff --git a/plugins/feature/gs232controller/gs232controllersettings.cpp b/plugins/feature/gs232controller/gs232controllersettings.cpp
index 29e616b5d..298f296e0 100644
--- a/plugins/feature/gs232controller/gs232controllersettings.cpp
+++ b/plugins/feature/gs232controller/gs232controllersettings.cpp
@@ -26,13 +26,15 @@
const QStringList GS232ControllerSettings::m_pipeTypes = {
QStringLiteral("ADSBDemod"),
QStringLiteral("Map"),
- QStringLiteral("StarTracker")
+ QStringLiteral("StarTracker"),
+ QStringLiteral("SatelliteTracker")
};
const QStringList GS232ControllerSettings::m_pipeURIs = {
QStringLiteral("sdrangel.channel.adsbdemod"),
QStringLiteral("sdrangel.feature.map"),
- QStringLiteral("sdrangel.feature.startracker")
+ QStringLiteral("sdrangel.feature.startracker"),
+ QStringLiteral("sdrangel.feature.satellitetracker")
};
GS232ControllerSettings::GS232ControllerSettings()
@@ -57,6 +59,10 @@ void GS232ControllerSettings::resetToDefaults()
m_reverseAPIFeatureIndex = 0;
m_azimuthOffset = 0;
m_elevationOffset = 0;
+ m_azimuthMin = 0;
+ m_azimuthMax = 450;
+ m_elevationMin = 0;
+ m_elevationMax = 180;
}
QByteArray GS232ControllerSettings::serialize() const
@@ -78,6 +84,10 @@ QByteArray GS232ControllerSettings::serialize() const
s.writeU32(14, m_reverseAPIFeatureIndex);
s.writeS32(15, m_azimuthOffset);
s.writeS32(16, m_elevationOffset);
+ s.writeS32(17, m_azimuthMin);
+ s.writeS32(18, m_azimuthMax);
+ s.writeS32(19, m_elevationMin);
+ s.writeS32(20, m_elevationMax);
return s.final();
}
@@ -122,6 +132,10 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data)
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
d.readS32(15, &m_azimuthOffset, 0);
d.readS32(16, &m_elevationOffset, 0);
+ d.readS32(17, &m_azimuthMin, 0);
+ d.readS32(18, &m_azimuthMax, 450);
+ d.readS32(19, &m_elevationMin, 0);
+ d.readS32(20, &m_elevationMax, 180);
return true;
}
diff --git a/plugins/feature/gs232controller/gs232controllersettings.h b/plugins/feature/gs232controller/gs232controllersettings.h
index 271f11239..83dd8b787 100644
--- a/plugins/feature/gs232controller/gs232controllersettings.h
+++ b/plugins/feature/gs232controller/gs232controllersettings.h
@@ -36,6 +36,10 @@ struct GS232ControllerSettings
QString m_target; // Plugin to get az/el from. E.g: "R0:0 ADSBDemod". Use a string, so can be set via WebAPI
int m_azimuthOffset;
int m_elevationOffset;
+ int m_azimuthMin;
+ int m_azimuthMax;
+ int m_elevationMin;
+ int m_elevationMax;
QString m_title;
quint32 m_rgbColor;
bool m_useReverseAPI;
diff --git a/plugins/feature/gs232controller/gs232controllerworker.cpp b/plugins/feature/gs232controller/gs232controllerworker.cpp
index 15a6ae453..5bfdaa6a4 100644
--- a/plugins/feature/gs232controller/gs232controllerworker.cpp
+++ b/plugins/feature/gs232controller/gs232controllerworker.cpp
@@ -16,6 +16,8 @@
// along with this program. If not, see . //
///////////////////////////////////////////////////////////////////////////////////
+#include
+
#include
#include
#include
@@ -35,7 +37,9 @@ GS232ControllerWorker::GS232ControllerWorker() :
m_msgQueueToFeature(nullptr),
m_msgQueueToGUI(nullptr),
m_running(false),
- m_mutex(QMutex::Recursive)
+ m_mutex(QMutex::Recursive),
+ m_lastAzimuth(-1),
+ m_lastElevation(-1)
{
connect(&m_pollTimer, SIGNAL(timeout()), this, SLOT(update()));
m_pollTimer.start(1000);
@@ -57,6 +61,7 @@ bool GS232ControllerWorker::startWork()
QMutexLocker mutexLocker(&m_mutex);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData);
+ openSerialPort(m_settings);
m_running = true;
return m_running;
}
@@ -64,6 +69,9 @@ bool GS232ControllerWorker::startWork()
void GS232ControllerWorker::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
+ // Close serial port as USB/controller activity can create RFI
+ if (m_serialPort.isOpen())
+ m_serialPort.close();
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
disconnect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData);
m_running = false;
@@ -104,71 +112,78 @@ void GS232ControllerWorker::applySettings(const GS232ControllerSettings& setting
<< " m_elevation: " << settings.m_elevation
<< " m_azimuthOffset: " << settings.m_azimuthOffset
<< " m_elevationOffset: " << settings.m_elevationOffset
+ << " m_azimuthMin: " << settings.m_azimuthMin
+ << " m_azimuthMax: " << settings.m_azimuthMax
+ << " m_elevationMin: " << settings.m_elevationMin
+ << " m_elevationMax: " << settings.m_elevationMax
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " force: " << force;
if ((settings.m_serialPort != m_settings.m_serialPort) || force)
{
- if (m_serialPort.isOpen())
- m_serialPort.close();
- m_serialPort.setPortName(settings.m_serialPort);
- m_serialPort.setBaudRate(settings.m_baudRate);
- if (!m_serialPort.open(QIODevice::ReadWrite))
- {
- qCritical() << "GS232ControllerWorker::applySettings: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error();
- if (m_msgQueueToFeature)
- m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error())));
- }
+ openSerialPort(settings);
}
else if ((settings.m_baudRate != m_settings.m_baudRate) || force)
{
m_serialPort.setBaudRate(settings.m_baudRate);
}
- if ((settings.m_elevation != m_settings.m_elevation)
- || (settings.m_elevationOffset != m_settings.m_elevationOffset)
- || force)
+ // Apply offset then clamp
+
+ int azimuth = settings.m_azimuth;
+ azimuth += settings.m_azimuthOffset;
+ azimuth = std::max(azimuth, settings.m_azimuthMin);
+ azimuth = std::min(azimuth, settings.m_azimuthMax);
+
+ int elevation = settings.m_elevation;
+ elevation += settings.m_elevationOffset;
+ elevation = std::max(elevation, settings.m_elevationMin);
+ elevation = std::min(elevation, settings.m_elevationMax);
+
+ if (((elevation != m_lastElevation) || force) && (settings.m_elevationMax != 0))
{
- setAzimuthElevation(settings.m_azimuth, settings.m_elevation, settings.m_azimuthOffset, settings.m_elevationOffset);
+ setAzimuthElevation(azimuth, elevation);
}
- else if ((settings.m_azimuth != m_settings.m_azimuth)
- || (settings.m_azimuthOffset != m_settings.m_azimuthOffset)
- || force)
+ else if ((azimuth != m_lastAzimuth) || force)
{
- setAzimuth(settings.m_azimuth, settings.m_azimuthOffset);
+ setAzimuth(azimuth);
}
m_settings = settings;
}
-void GS232ControllerWorker::setAzimuth(int azimuth, int azimuthOffset)
+void GS232ControllerWorker::openSerialPort(const GS232ControllerSettings& settings)
+{
+ if (m_serialPort.isOpen())
+ m_serialPort.close();
+ m_serialPort.setPortName(settings.m_serialPort);
+ m_serialPort.setBaudRate(settings.m_baudRate);
+ if (!m_serialPort.open(QIODevice::ReadWrite))
+ {
+ qCritical() << "GS232ControllerWorker::openSerialPort: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error();
+ if (m_msgQueueToFeature)
+ m_msgQueueToFeature->push(GS232Controller::MsgReportWorker::create(QString("Failed to open serial port %1: %2").arg(settings.m_serialPort).arg(m_serialPort.error())));
+ }
+ m_lastAzimuth = -1;
+ m_lastElevation = -1;
+}
+
+void GS232ControllerWorker::setAzimuth(int azimuth)
{
- azimuth += azimuthOffset;
- if (azimuth < 0)
- azimuth = 0;
- else if (azimuth > 450)
- azimuth = 450;
QString cmd = QString("M%1\r\n").arg(azimuth, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
+ m_lastAzimuth = azimuth;
}
-void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset)
+void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation)
{
- azimuth += azimuthOffset;
- if (azimuth < 0)
- azimuth = 0;
- else if (azimuth > 450)
- azimuth = 450;
- elevation += elevationOffset;
- if (elevation < 0)
- elevation = 0;
- else if (elevation > 180)
- elevation = 180;
QString cmd = QString("W%1 %2\r\n").arg(azimuth, 3, 10, QLatin1Char('0')).arg(elevation, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
+ m_lastAzimuth = azimuth;
+ m_lastElevation = elevation;
}
void GS232ControllerWorker::readSerialData()
diff --git a/plugins/feature/gs232controller/gs232controllerworker.h b/plugins/feature/gs232controller/gs232controllerworker.h
index 3be417fe2..0bf22cace 100644
--- a/plugins/feature/gs232controller/gs232controllerworker.h
+++ b/plugins/feature/gs232controller/gs232controllerworker.h
@@ -76,11 +76,15 @@ private:
QSerialPort m_serialPort;
QTimer m_pollTimer;
+ int m_lastAzimuth;
+ int m_lastElevation;
+
bool handleMessage(const Message& cmd);
void applySettings(const GS232ControllerSettings& settings, bool force = false);
MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; }
- void setAzimuth(int azimuth, int azimuthOffset);
- void setAzimuthElevation(int azimuth, int elevation, int azimuthOffset, int elevationOffset);
+ void openSerialPort(const GS232ControllerSettings& settings);
+ void setAzimuth(int azimuth);
+ void setAzimuthElevation(int azimuth, int elevation);
private slots:
void handleInputMessages();
diff --git a/plugins/feature/gs232controller/readme.md b/plugins/feature/gs232controller/readme.md
index 8432cc5a6..854a336c9 100644
--- a/plugins/feature/gs232controller/readme.md
+++ b/plugins/feature/gs232controller/readme.md
@@ -54,6 +54,23 @@ The azimuth offset specifies an angle in degrees that is added to the target azi
The elevation offset specifies an angle in degrees that is added to the target elevation before sending to the controller. This allows for a misalignment of the rotator to be corrected.
+
11 and 12: Azimuth Min and Max
+
+The azimuth min and max values specify the minimum and maximum azimuth values (after offset has been applied), that will be sent to the rotator.
+These values can be used to prevent the rotator from rotating an antenna in to an obstable.
+
+
13 and 14: Elevation Min and Max
+
+The elevation min and max values specify the minimum and maximum elevation values (after offset has been applied), that will be sent to the rotator.
+These values can be used to prevent the rotator from rotating an antenna in to an obstable.
+If the maximum elevation is set to 0, the controller will only use the M GS-232 command, rather than M and W.
+
+
GS-232 Protocol Implementation
+
+The controller uses the Waaa eee command when elevation needs to be set.
+When only azimuth needs to be set, the Maaa command is used.
+The C2 command is used to read current azimuth and elevation. A response of AZ=aaaEL=eee is expected.
+
The Map Feature plugin displays a world map. It can display street maps, satellite imagery as well as custom map types.
-On top of this, it can plot data from other plugins, such as APRS symbols from the APRS Feature, aircraft from the ADS-B Demodulator
-or the Sun, Moon and Stars from the Star Tracker. It can also display beacon locations based on the IARU Region 1 beacon database.
+On top of this, it can plot data from other plugins, such as:
+
+* APRS symbols from the APRS Feature,
+* Aircraft from the ADS-B Demodulator,
+* Satellites from the Satellite Tracker,
+* The Sun, Moon and Stars from the Star Tracker,
+* Beacons based on the IARU Region 1 beacon database.
+
+It can also create tracks showing the path aircraft and APRS objects have taken, as well as predicted paths for satellites.

@@ -44,15 +51,24 @@ The beacons will then be displayed in the table and on the map.
When checked, names of objects are displayed in a bubble next to each object.
-
6: Delete
+
6: Display tracks for selected object
+
+When checked, displays the track (taken or predicted) for the selected object.
+
+
7: Display tracks for all objects
+
+When checked, displays the track (taken or predicted) for the all objects.
+
+
8: Delete
When clicked, all items will be deleted from the map.
-
7: Display settings
+
9: Display settings
When clicked, opens the Map Display Settings dialog, which allows setting:
* Which data the Map will display.
+* The colour of the taken and predicted tracks.
* Which Map provider will be used to source the map image.
In order to display Mapbox maps, you will need to enter an API Key. A key can be obtained by registering at: http://www.mapbox.com/
diff --git a/plugins/feature/satellitetracker/CMakeLists.txt b/plugins/feature/satellitetracker/CMakeLists.txt
new file mode 100644
index 000000000..ccf56fd06
--- /dev/null
+++ b/plugins/feature/satellitetracker/CMakeLists.txt
@@ -0,0 +1,83 @@
+project(satellitetracker)
+
+set(satellitetracker_SOURCES
+ satellitetracker.cpp
+ satellitetrackersettings.cpp
+ satellitetrackerplugin.cpp
+ satellitetrackerworker.cpp
+ satellitetrackerwebapiadapter.cpp
+ satellitetrackersgp4.cpp
+)
+
+set(satellitetracker_HEADERS
+ satellitetracker.h
+ satellitetrackersettings.h
+ satellitetrackerplugin.h
+ satellitetrackerreport.h
+ satellitetrackerworker.h
+ satellitetrackerwebapiadapter.h
+ satellitetrackersgp4.h
+)
+
+include_directories(
+ ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
+ ${SGP4_INCLUDE_DIR}
+)
+
+if(NOT SERVER_MODE)
+ set(satellitetracker_SOURCES
+ ${satellitetracker_SOURCES}
+ satellitetrackergui.cpp
+ satellitetrackergui.ui
+ satellitetrackersettingsdialog.cpp
+ satellitetrackersettingsdialog.ui
+ satellitetracker.qrc
+ satelliteselectiondialog.cpp
+ satelliteselectiondialog.ui
+ satelliteradiocontroldialog.cpp
+ satelliteradiocontroldialog.ui
+ satellitedevicesettingsgui.cpp
+ )
+ set(satellitetracker_HEADERS
+ ${satellitetracker_HEADERS}
+ satellitetrackergui.h
+ satellitetrackersettingsdialog.h
+ satelliteselectiondialog.h
+ satelliteradiocontroldialog.h
+ satellitedevicesettingsgui.h
+ )
+
+ set(TARGET_NAME featuresatellitetracker)
+ set(TARGET_LIB Qt5::Widgets Qt5::Positioning Qt5::Charts Qt5::TextToSpeech)
+ set(TARGET_LIB_GUI "sdrgui")
+ set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
+else()
+ set(TARGET_NAME featuresatellitetrackersrv)
+ set(TARGET_LIB Qt5::Positioning)
+ set(TARGET_LIB_GUI "")
+ set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
+endif()
+
+add_library(${TARGET_NAME} SHARED
+ ${satellitetracker_SOURCES}
+)
+
+if(SGP4_EXTERNAL)
+ add_dependencies(${TARGET_NAME} sgp4)
+endif()
+
+target_link_libraries(${TARGET_NAME}
+ Qt5::Core
+ ${TARGET_LIB}
+ sdrbase
+ ${TARGET_LIB_GUI}
+ ${SGP4_LIBRARIES}
+)
+
+install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
+
+if(WIN32)
+ # Run deployqt for Charts and TextToSpeech etc
+ include(DeployQt)
+ windeployqt(${TARGET_NAME} ${SDRANGEL_BINARY_BIN_DIR} ${PROJECT_SOURCE_DIR}/aprs)
+endif()
diff --git a/plugins/feature/satellitetracker/readme.md b/plugins/feature/satellitetracker/readme.md
new file mode 100644
index 000000000..e85408553
--- /dev/null
+++ b/plugins/feature/satellitetracker/readme.md
@@ -0,0 +1,197 @@
+
Satellite Tracker Feature Plugin
+
+
Introduction
+
+The Satellite Tracker feature plugin can be used to:
+
+* Track satellites, pointing antennas at them via SDRangel's Rotator Controller Features
+* Control SDRangel by loading presets, starting/stopping acqusition and setting center frequenies on AOS (Acquisition of Signal) for each satellite
+* Adjust channels' input frequency offset to account for Doppler shift
+* Display polar and elevation/azimuth vs time plots for satellite passes
+* Display the overhead position of satellites on the Map Feature, along with the ground track of the satellites
+* Display a variety of information about the satellite
+
+
+
+
+
+This button starts or stops the satellite tracking. The plugin will only calculate satellite positions or adjust for Doppler when started.
+
+
2: Find satellite on map
+
+Pressing this button centres the Map Feature (if open) on the target satellite.
+
+
3: Automatically select target on AOS
+
+When checked, the target satellite will be automatically changed on any selected satellite's AOS, if it is a higher priority than the current target or if the current target satellite is not visible.
+Priority is determined by the order the satellites appear in the Satellite Selection dialog.
+
+
4: Update satellite data
+
+When clicked, the TLE (two line element) files selected in the Settings dialog are downloaded as well as the latest SatNogs satellite database, containing details of satellite's transmitter and receiver frequencies. While downloading, this button will appear green.
+
+Satellite positions can only be predicted with limited accuracy, so without the TLEs need to be updated frequently for accurate positioning. This could be daily, weekly or monthly depending upon the individual satellite. This downloads around 1MB of data.
+
+
5: Show SDRangel Control dialog
+
+Pressing this button displays the SDRangel Control dialog.
+
+
+
+This dialog determines the actions the Satellite Tracker will take when AOS or LOS occurs for a satellite. First, select a satellite from the dropdown box. Information about the satellites transmit and receive modes should appear in the field at the bottom of the dialog, if available in the SatNogs database.
+
+To perform an action on an SDRangel device set on AOS or LOS, press the + button. This will add a row in the table, allowing you to select:
+
+* The device set that will be controlled. This will list all currently open device sets. You can also type the name of a new device set.
+* The preset to load on AOS. This allows preset device settings (E.g. centre frequency) and demodulators to be opened when the satellite becomes visible.
+* Which channels Doppler correction should be applied to. The list of channels is taken from the selected preset. Check a channel to enable Doppler correct for that channel. The Doppler correction is applied to the channel's input frequency offset.
+* Whether to start acquisition (i.e. start the DDR device) on AOS.
+* Whether to start acquisition on LOS.
+* Whether and file sinks in the preset should be started on AOS and stopped on LOS. This allows the baseband signal received from the satellite to be recorded to a file.
+* Whether to override the centre frequency in the preset. This allows a single preset to be used with multiple satellites.
+* A command or script to execute on AOS.
+* A command or script to execute on LOS.
+
+Multiple rows can be added, to allow independent control of multiple device sets. To remove a row, select the row by clicking the row number, then press the - button.
+
+
6: Show Satellite Selection dialog
+
+Pressing this button displays the Satellite Selection dialog.
+
+
+
+On the left hand side are a list of all available satellites, as determined by the TLE files that have been downloaded. (If none are visible, ensure the TLEs tab of the Satellite Settings dialog (8) contains at least https://db.satnogs.org/api/tle/ and then press the Update satellite data (4) button)
+
+The list of satellites that the Satellite Tracker will track is on the right hand side.
+
+To move satellites from side to side, either double click them, or select them and press the left or right arrows in the middle.
+
+The Satellites to track list is ordered in priority for the auto target feature (3). The change the order, select a satellite in the list and press the up or down arrows to the right.
+
+Satellite information at the bottom of the dialog comes from the SatNogs database: https://db.satnogs.org/
+
+
7: Set latitude and longitude from My Position
+
+When clicked, it sets the latitude, longitude and height fields to the values from SDRangel's My Position preferences.
+
+
8: Show Settings dialog
+
+Pressing this button displays the Settings dialog.
+
+
+
+On the Settings tab, you can set:
+
+* Height above sea level in metres of the anntenna.
+* The prediciton period in days. This limits the maximum number of days ahead for which satellite passes are predicted until.
+* The minimum elevation in degrees from the antenna location, which a satellite much reach in order for AOS to be indicated.
+* The minimum elevation in degrees from the antenna location, which a satellite much reach in order for a pass to be indicated.
+* A time window for which passes must start and end between, to be displayed or acted upon. For example, for day time passes, you could set "must start after" to 8:00 and "must end before" to 18:00. For night time passes, set "must start after" to 20:00 and "must end before" to 6:00.
+* The maximum azimuth angle in degrees supported by your rotator. 450 degree support is beneficial for passes that pass through 360/0 degrees, to avoid the rotator having to do a complete rotation mid pass.
+* The maximum elevation angle in degrees supported by your rotator. 180 degree support is beneficial for passes that pass through 360/0 degrees, to avoid the rotator having to do a complete rotation mid pass.
+* A speech warning to be given on AOS. ${name} will be subsitited with the name of the satellite, ${duration} the pass duration and ${elevation} the maximum elevation of the pass.
+* A speech warning to be given on LOS. ${name} will be subsitited with the name of the satellite.
+* A command/script to be executed on AOS. This applies to all satellites. It is also possible to set a per-satellite command in the SDRangel Control dialog.
+* A command/script to be executed on LOS. This applies to all satellites. It is also possible to set a per-satellite command in the SDRangel Control dialog.
+* The Doppler correction period in seconds, which controls how frequently Doppler correction is applied. Which channels have Doppler correction applied is set on a per-channel basis in the SDRangel Control dialog.
+
+
+
+On the TLEs tab, you can provide a list of URL from which satellite Two Line Element files can be downloaded from.
+TLE files contain the orbital parameters for a satellite and are required in order to be able to calculate a satellites position.
+
+
+
+On the display tab, you can set:
+
+* The update period in seconds, which controls how frequently satellite positions are calculated.
+* The default frequency in MHz that is used for calculating Doppler and free space path loss in the Satellite Data table.
+* The units used to display azimuth and elevation to the target satellite. This can be in degrees, minutes and seconds or decimal degrees.
+* The number of points used for ground tracks on the map. More points result in smoother tracks, but require more processing.
+* Whether times are display in the local time zone or UTC.
+* Whether to draw the satellites on the map.
+
+
9: Latitude
+
+Specifies the latitude in decimal degrees (North positive) of the antenna location.
+
+
10: Longitude
+
+Specifies the longitude in decimal degrees (East positive) of the antenna location.
+
+
11: Time
+
+Select the date and time at which the position of the satellite should be calculated. Select either Now, for the current time, or Custom to manually enter a date and time.
+
+
12: Target
+
+Select the target satellite. The target satellite is the source of data for the Time to AOS, Azimuth and Elevation fields. The azimuth and elevation of the target satellite is sent to the Rotator Controller features.
+
+
13: Time to AOS
+
+This field displays the time to AOS (Acquisition of Signal) for the target satellite. It is displayed in hours, minutes and seconds, unless the satellite is currently visible, in which case it will display "Now".
+
+
14: Azimuth
+
+Displays the calculated azimuth (angle in degrees, clockwise from North) to the target satellite.
+
+
15: Elevation
+
+Displays the calculated elevation (angle in degrees - 0 to horizon and 90 to zenith) to the target satellite.
+
+
Pass Charts
+
+Pass charts can be plotted showing the azimuth and elevation of the target satellite from AOS to LOS. This can be in polar of Cartesian form:
+
+
+
+The arrows next to the chart combobox, allow the pass number to be selected. Pass 0 is the next pass, with higher numbered passes occuring later in time.
+The amount of passes is determined by the prediction period, which can be set in the Settings dialog.
+
+
Satellite Data
+
+The satellite data table displays calculated data about the selected satellites.
+
+
+
+The table contains:
+
+* The satellite name.
+* The azimuth in degrees to the satellite from the antenna location.
+* The elevation in degress to the satellite from the antenna location.
+* The time of the next AOS. If time is some days in the future, the number of days will be displayed as +days. E.g. +1 for tomorrow.
+* The time of the next LOS.
+* The maximum elevation in degrees that the satellite will be from the antenna location in the next pass.
+* Whether the satellite will be heading South to North (up addow) or North to South (down arrow) in the next pass.
+* The altitude of the satellite in kilometres.
+* The range to the satellite from the antenna location in kilometers.
+* The range range (i.e. speed the satellite is moving away from the antenna location) in kilometres per second.
+* The Doppler shift due to the satellite's motion that would be observed on a signal at the default frequency (which can be set in the Settings dialog).
+* The free space path loss to the satellite, at the default frequency.
+* The one-way propagation delay to the satellite from the antenna location in milliseconds.
+* The NORAD catalog identifier for the satellite.
+
+Rows can be ordered by left clicking column headers.
+Columns can be hidden by right clicking on the header and unchecking them.
+
+
Map
+
+The Satellite Tracker feature can send the overhead position of the satellite to the Map, along with a ground track.
+
+When using the Find feature in the Map GUI, you can search by the name of the satellite.
+
+
+
+
Attribution
+
+sgp4 library by Daniel Warner https://github.com/dnwrnr
+
+SatNogs satellite database https://db.satnogs.org/
+
+Satellite two-line elements (TLEs) are from Celestrak https://celestrak.com/
+
+Icons are by Freepik from Flaticon https://www.flaticon.com/
diff --git a/plugins/feature/satellitetracker/satellitedevicesettingsgui.cpp b/plugins/feature/satellitetracker/satellitedevicesettingsgui.cpp
new file mode 100644
index 000000000..83e610600
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitedevicesettingsgui.cpp
@@ -0,0 +1,291 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+
+#include "satellitedevicesettingsgui.h"
+#include "device/deviceset.h"
+#include "settings/mainsettings.h"
+#include "maincore.h"
+#include "util/messagequeue.h"
+#include "plugin/pluginmanager.h"
+#include "plugin/pluginapi.h"
+
+SatelliteDeviceSettingsGUI::SatelliteDeviceSettingsGUI(SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings,
+ QTableWidget *table)
+{
+ m_devSettings = devSettings;
+
+ // Device set
+ m_deviceSetWidget = new QComboBox();
+ m_deviceSetWidget->setEditable(true);
+ m_deviceSetWidget->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_DEVICESET)->toolTip());
+ m_deviceSetItem = new QWidget();
+ layout(m_deviceSetItem, m_deviceSetWidget);
+ addDeviceSets();
+ int devSetIdx = m_deviceSetWidget->findText(devSettings->m_deviceSet);
+ if (devSetIdx != -1)
+ m_deviceSetWidget->setCurrentIndex(devSetIdx);
+ else
+ {
+ m_deviceSetWidget->addItem(devSettings->m_deviceSet);
+ m_deviceSetWidget->setCurrentIndex(m_deviceSetWidget->count() - 1);
+ }
+
+ // Preset
+ m_presetWidget = new QComboBox();
+ m_presetWidget->setEditable(false);
+ m_presetWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ m_presetWidget->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_PRESET)->toolTip());
+ m_presetItem = new QWidget();
+ layout(m_presetItem, m_presetWidget);
+ addPresets(devSettings->m_deviceSet);
+
+ const MainSettings& mainSettings = MainCore::instance()->getSettings();
+ if (!devSettings->m_deviceSet.isEmpty())
+ {
+ int count = mainSettings.getPresetCount();
+ int idx = 0;
+ for (int i = 0; i < count; i++)
+ {
+ const Preset *preset = mainSettings.getPreset(i);
+ if ( ((preset->isSourcePreset() && (devSettings->m_deviceSet[0] == "R")))
+ || ((preset->isSinkPreset() && (devSettings->m_deviceSet[0] == "T")))
+ || ((preset->isMIMOPreset() && (devSettings->m_deviceSet[0] == "M"))))
+ {
+ if ( (devSettings->m_presetGroup == preset->getGroup())
+ && (devSettings->m_presetFrequency == preset->getCenterFrequency())
+ && (devSettings->m_presetDescription == preset->getDescription()))
+ {
+ m_presetWidget->setCurrentIndex(idx);
+ break;
+ }
+ idx++;
+ }
+ }
+ }
+
+ // Doppler
+ m_dopplerWidget = new QComboBox();
+ m_dopplerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ m_dopplerWidget->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_DOPPLER)->toolTip());
+ m_dopplerItem = new QWidget();
+ layout(m_dopplerItem, m_dopplerWidget);
+ m_dopplerWidget->setModel(&m_dopplerModel);
+ addChannels();
+
+ for (int i = 0; i < devSettings->m_doppler.size(); i++)
+ m_dopplerItems[devSettings->m_doppler[i]]->setData(Qt::Checked, Qt::CheckStateRole);
+
+ // Start on AOS
+ m_startOnAOSWidget = new QCheckBox();
+ m_startOnAOSWidget->setChecked(devSettings->m_startOnAOS);
+ m_startOnAOSWidget->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_START)->toolTip());
+ m_startOnAOSItem = new QWidget();
+ layout(m_startOnAOSItem, m_startOnAOSWidget);
+
+ // Stop on AOS
+ m_stopOnLOSWidget = new QCheckBox();
+ m_stopOnLOSWidget->setChecked(devSettings->m_stopOnLOS);
+ m_stopOnLOSWidget->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_STOP)->toolTip());
+ m_stopOnLOSItem = new QWidget();
+ layout(m_stopOnLOSItem, m_stopOnLOSWidget);
+
+ // Start file sink
+ m_startStopFileSinkWidget = new QCheckBox();
+ m_startStopFileSinkWidget->setChecked(devSettings->m_startStopFileSink);
+ m_startStopFileSinkWidget->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_START_FILE_SINK)->toolTip());
+ m_startStopFileSinkItem = new QWidget();
+ layout(m_startStopFileSinkItem, m_startStopFileSinkWidget);
+
+ // Frequency override
+ m_frequencyItem = new QTableWidgetItem();
+ m_frequencyItem->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_FREQUENCY)->toolTip());
+ if (devSettings->m_frequency != 0)
+ m_frequencyItem->setData(Qt::DisplayRole, QString("%1").arg(devSettings->m_frequency/1000000.0, 0, 'f', 3, QLatin1Char(' ')));
+
+ // AOS command
+ m_aosCommandItem = new QTableWidgetItem();
+ m_aosCommandItem->setText(devSettings->m_aosCommand);
+ m_aosCommandItem->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_AOS_COMMAND)->toolTip());
+
+ // LOS command
+ m_losCommandItem = new QTableWidgetItem();
+ m_losCommandItem->setText(devSettings->m_losCommand);
+ m_losCommandItem->setToolTip(table->horizontalHeaderItem(SAT_DEVICE_COL_LOS_COMMAND)->toolTip());
+
+ int row = table->rowCount();
+ table->setRowCount(row + 1);
+ table->setCellWidget(row, SAT_DEVICE_COL_DEVICESET, m_deviceSetItem);
+ table->setCellWidget(row, SAT_DEVICE_COL_PRESET, m_presetItem);
+ table->setCellWidget(row, SAT_DEVICE_COL_DOPPLER, m_dopplerItem);
+ table->setCellWidget(row, SAT_DEVICE_COL_START, m_startOnAOSItem);
+ table->setCellWidget(row, SAT_DEVICE_COL_STOP, m_stopOnLOSItem);
+ table->setCellWidget(row, SAT_DEVICE_COL_START_FILE_SINK, m_startStopFileSinkItem);
+ table->setItem(row, SAT_DEVICE_COL_FREQUENCY, m_frequencyItem);
+ table->setItem(row, SAT_DEVICE_COL_AOS_COMMAND, m_aosCommandItem);
+ table->setItem(row, SAT_DEVICE_COL_LOS_COMMAND, m_losCommandItem);
+ table->resizeColumnsToContents();
+
+ connect(m_deviceSetWidget, SIGNAL(currentTextChanged(const QString &)), this, SLOT(on_m_deviceSetWidget_currentTextChanged(const QString &)));
+ connect(m_presetWidget, SIGNAL(currentIndexChanged(int)), this, SLOT(on_m_presetWidget_currentIndexChanged(int)));
+}
+
+void SatelliteDeviceSettingsGUI::layout(QWidget *parent, QWidget *child)
+{
+ QHBoxLayout* pLayout = new QHBoxLayout(parent);
+ pLayout->addWidget(child);
+ pLayout->setAlignment(Qt::AlignCenter);
+ pLayout->setContentsMargins(0, 0, 0, 0);
+ parent->setLayout(pLayout);
+}
+
+// Add available devicesets to the combobox
+void SatelliteDeviceSettingsGUI::addDeviceSets()
+{
+ MainCore *mainCore = MainCore::instance();
+ std::vector& deviceSets = mainCore->getDeviceSets();
+ std::vector::const_iterator it = deviceSets.begin();
+ for (unsigned int deviceIndex = 0; it != deviceSets.end(); ++it, deviceIndex++)
+ {
+ DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
+ DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine;
+
+ if (deviceSourceEngine) {
+ m_deviceSetWidget->addItem(QString("R%1").arg(deviceIndex), deviceIndex);
+ } else if (deviceSinkEngine) {
+ m_deviceSetWidget->addItem(QString("T%1").arg(deviceIndex), deviceIndex);
+ }
+ }
+}
+
+// Add all available presets for a deviceset to the combobox
+void SatelliteDeviceSettingsGUI::addPresets(const QString& deviceSet)
+{
+ m_presetWidget->clear();
+ const MainSettings& mainSettings = MainCore::instance()->getSettings();
+ int count = mainSettings.getPresetCount();
+ m_currentPresets = deviceSet[0];
+ for (int i = 0; i < count; i++)
+ {
+ const Preset *preset = mainSettings.getPreset(i);
+ if ( ((preset->isSourcePreset() && (m_currentPresets == "R")))
+ || ((preset->isSinkPreset() && (m_currentPresets == "T")))
+ || ((preset->isMIMOPreset() && (m_currentPresets == "M"))))
+ {
+ m_presetWidget->addItem(QString("%1: %2 - %3")
+ .arg(preset->getGroup())
+ .arg(preset->getCenterFrequency()/1000000.0, 0, 'f', 3)
+ .arg(preset->getDescription()));
+ }
+ }
+}
+
+const Preset* SatelliteDeviceSettingsGUI::getSelectedPreset()
+{
+ int listIdx = m_presetWidget->currentIndex();
+ const MainSettings& mainSettings = MainCore::instance()->getSettings();
+ int count = mainSettings.getPresetCount();
+ int presetIdx = 0;
+ for (int i = 0; i < count; i++)
+ {
+ const Preset *preset = mainSettings.getPreset(i);
+ if ( ((preset->isSourcePreset() && (m_currentPresets == "R")))
+ || ((preset->isSinkPreset() && (m_currentPresets == "T")))
+ || ((preset->isMIMOPreset() && (m_currentPresets == "M"))))
+ {
+ if (listIdx == presetIdx)
+ return preset;
+ presetIdx++;
+ }
+ }
+ return nullptr;
+}
+
+// Add checkable list of channels from a preset to the combobox
+void SatelliteDeviceSettingsGUI::addChannels()
+{
+ m_dopplerModel.clear();
+ m_dopplerItems.clear();
+ const PluginManager *pluginManager = MainCore::instance()->getPluginManager();
+ const Preset* preset = getSelectedPreset();
+ if (preset != nullptr)
+ {
+ int channels = preset->getChannelCount();
+ for (int i = 0; i < channels; i++)
+ {
+ const Preset::ChannelConfig& channelConfig = preset->getChannelConfig(i);
+
+ QStandardItem *item = new QStandardItem();
+ item->setText(pluginManager->uriToId(channelConfig.m_channelIdURI));
+ item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ item->setData(Qt::Unchecked, Qt::CheckStateRole);
+ m_dopplerModel.appendRow(item);
+ m_dopplerItems.append(item);
+ }
+ }
+}
+
+// Update preset list, to match type of deviceset entered
+void SatelliteDeviceSettingsGUI::on_m_deviceSetWidget_currentTextChanged(const QString &text)
+{
+ if (!text.isEmpty())
+ {
+ if (text[0] != m_currentPresets)
+ addPresets(text[0]);
+ }
+}
+
+// Update doppler combo, to correspond to selected preset
+void SatelliteDeviceSettingsGUI::on_m_presetWidget_currentIndexChanged(int index)
+{
+ (void) index;
+ addChannels();
+}
+
+// Update devSettings with current GUI values
+void SatelliteDeviceSettingsGUI::accept()
+{
+ m_devSettings->m_deviceSet = m_deviceSetWidget->currentText();
+ const Preset* preset = getSelectedPreset();
+ if (preset != nullptr)
+ {
+ m_devSettings->m_presetGroup = preset->getGroup();
+ m_devSettings->m_presetFrequency = preset->getCenterFrequency();
+ m_devSettings->m_presetDescription = preset->getDescription();
+ }
+ else
+ {
+ m_devSettings->m_presetGroup = "";
+ m_devSettings->m_presetFrequency = 0;
+ m_devSettings->m_presetDescription = "";
+ }
+ m_devSettings->m_doppler.clear();
+ for (int i = 0; i < m_dopplerItems.size(); i++)
+ {
+ if (m_dopplerItems[i]->checkState() == Qt::Checked)
+ m_devSettings->m_doppler.append(i);
+ }
+ m_devSettings->m_startOnAOS = m_startOnAOSWidget->isChecked();
+ m_devSettings->m_stopOnLOS = m_stopOnLOSWidget->isChecked();
+ m_devSettings->m_startStopFileSink = m_startStopFileSinkWidget->isChecked();
+ m_devSettings->m_frequency = (quint64)(m_frequencyItem->data(Qt::DisplayRole).toDouble() * 1000000.0);
+ m_devSettings->m_aosCommand = m_aosCommandItem->text();
+ m_devSettings->m_losCommand = m_losCommandItem->text();
+}
diff --git a/plugins/feature/satellitetracker/satellitedevicesettingsgui.h b/plugins/feature/satellitetracker/satellitedevicesettingsgui.h
new file mode 100644
index 000000000..9e43c603b
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitedevicesettingsgui.h
@@ -0,0 +1,94 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITEDEVICESETTINGSGUI_H
+#define INCLUDE_FEATURE_SATELLITEDEVICESETTINGSGUI_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "settings/preset.h"
+#include "satellitetrackersettings.h"
+
+class SatelliteRadioControlDialog;
+
+class SatelliteDeviceSettingsGUI : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ SatelliteDeviceSettingsGUI(SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings,
+ QTableWidget *table);
+ void accept();
+
+protected:
+
+ void layout(QWidget *parent, QWidget *child);
+ void addDeviceSets();
+ void addPresets(const QString& deviceSet);
+ void addChannels();
+ const Preset *getSelectedPreset();
+
+private slots:
+
+ void on_m_deviceSetWidget_currentTextChanged(const QString &text);
+ void on_m_presetWidget_currentIndexChanged(int index);
+
+protected:
+
+ friend SatelliteRadioControlDialog;
+ QWidget *m_deviceSetItem;
+ QComboBox *m_deviceSetWidget;
+ QWidget *m_presetItem;
+ QComboBox *m_presetWidget;
+ QWidget *m_dopplerItem;
+ QComboBox *m_dopplerWidget;
+ QWidget *m_startOnAOSItem;
+ QCheckBox *m_startOnAOSWidget;
+ QWidget *m_stopOnLOSItem;
+ QCheckBox *m_stopOnLOSWidget;
+ QWidget *m_startStopFileSinkItem;
+ QCheckBox *m_startStopFileSinkWidget;
+ QTableWidgetItem *m_frequencyItem;
+ QTableWidgetItem *m_aosCommandItem;
+ QTableWidgetItem *m_losCommandItem;
+ QChar m_currentPresets;
+
+ QStandardItemModel m_dopplerModel;
+ QList m_dopplerItems;
+
+ SatelliteTrackerSettings::SatelliteDeviceSettings *m_devSettings;
+
+ enum SatDeviceCol {
+ SAT_DEVICE_COL_DEVICESET,
+ SAT_DEVICE_COL_PRESET,
+ SAT_DEVICE_COL_DOPPLER,
+ SAT_DEVICE_COL_START,
+ SAT_DEVICE_COL_STOP,
+ SAT_DEVICE_COL_START_FILE_SINK,
+ SAT_DEVICE_COL_FREQUENCY,
+ SAT_DEVICE_COL_AOS_COMMAND,
+ SAT_DEVICE_COL_LOS_COMMAND
+ };
+};
+
+#endif // INCLUDE_FEATURE_SATELLITEDEVICESETTINGSGUI_H
diff --git a/plugins/feature/satellitetracker/satelliteradiocontroldialog.cpp b/plugins/feature/satellitetracker/satelliteradiocontroldialog.cpp
new file mode 100644
index 000000000..a8fdefd38
--- /dev/null
+++ b/plugins/feature/satellitetracker/satelliteradiocontroldialog.cpp
@@ -0,0 +1,149 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+
+#include "device/deviceset.h"
+#include "settings/mainsettings.h"
+#include "settings/preset.h"
+#include "maincore.h"
+#include "util/messagequeue.h"
+#include "satelliteradiocontroldialog.h"
+
+SatelliteRadioControlDialog::SatelliteRadioControlDialog(SatelliteTrackerSettings *settings,
+ const QHash& satellites,
+ QWidget* parent) :
+ QDialog(parent),
+ m_settings(settings),
+ m_satellites(satellites),
+ ui(new Ui::SatelliteRadioControlDialog)
+{
+ ui->setupUi(this);
+
+ // Must resize before setting m_deviceSettings
+ resizeTable();
+
+ m_deviceSettings = m_settings->m_deviceSettings;
+
+ for (int i = 0; i < settings->m_satellites.size(); i++)
+ ui->satelliteSelect->addItem(settings->m_satellites[i]);
+}
+
+SatelliteRadioControlDialog::~SatelliteRadioControlDialog()
+{
+ delete ui;
+}
+
+void SatelliteRadioControlDialog::accept()
+{
+ for (int i = 0; i < m_devSettingsGUIs.size(); i++)
+ m_devSettingsGUIs[i]->accept();
+ QDialog::accept();
+ m_settings->m_deviceSettings = m_deviceSettings;
+}
+
+void SatelliteRadioControlDialog::resizeTable()
+{
+ on_add_clicked();
+ ui->table->resizeColumnsToContents();
+ ui->table->selectRow(0);
+ on_remove_clicked();
+ ui->table->selectRow(-1);
+}
+
+void SatelliteRadioControlDialog::on_add_clicked()
+{
+ QString name = ui->satelliteSelect->currentText();
+ if (!name.isEmpty())
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = new SatelliteTrackerSettings::SatelliteDeviceSettings();
+ SatelliteDeviceSettingsGUI *devSettingsGUI = new SatelliteDeviceSettingsGUI(devSettings, ui->table);
+
+ m_devSettingsGUIs.append(devSettingsGUI);
+ QList *devSettingsList = m_deviceSettings.value(name);
+ devSettingsList->append(devSettings);
+ }
+}
+
+// Remove selected row
+void SatelliteRadioControlDialog::on_remove_clicked()
+{
+ // Selection mode is single, so only a single row should be returned
+ QModelIndexList indexList = ui->table->selectionModel()->selectedRows();
+ if (!indexList.isEmpty())
+ {
+ int row = indexList.at(0).row();
+ ui->table->removeRow(row);
+ delete m_devSettingsGUIs.takeAt(row);
+
+ QString name = ui->satelliteSelect->currentText();
+ QList *devSettingsList = m_deviceSettings.value(name);
+ delete devSettingsList->takeAt(row);
+ }
+}
+
+void SatelliteRadioControlDialog::on_satelliteSelect_currentIndexChanged(int index)
+{
+ (void) index;
+
+ // Save details from current GUI elements
+ for (int i = 0; i < m_devSettingsGUIs.size(); i++)
+ m_devSettingsGUIs[i]->accept();
+ // Clear GUI
+ ui->table->setRowCount(0);
+ qDeleteAll(m_devSettingsGUIs);
+ m_devSettingsGUIs.clear();
+
+ // Create settings list for newly selected satellite, if one doesn't already exist
+ QString name = ui->satelliteSelect->currentText();
+ if (!m_deviceSettings.contains(name))
+ m_deviceSettings.insert(name, new QList());
+
+ // Add existing settings to GUI
+ QList *devSettingsList = m_deviceSettings.value(name);
+ for (int i = 0; i < devSettingsList->size(); i++)
+ {
+ SatelliteDeviceSettingsGUI *devSettingsGUI = new SatelliteDeviceSettingsGUI(devSettingsList->at(i), ui->table);
+ m_devSettingsGUIs.append(devSettingsGUI);
+ }
+
+ // Display modes for the satellite, to help user select appropriate presets
+ SatNogsSatellite *sat = m_satellites[name];
+ QStringList info;
+ for (int i = 0; i < sat->m_transmitters.size(); i++)
+ {
+ if (sat->m_transmitters[i]->m_status != "invalid")
+ {
+ QStringList mode;
+ mode.append(" ");
+ mode.append(sat->m_transmitters[i]->m_description);
+ if (sat->m_transmitters[i]->m_downlinkHigh > 0)
+ mode.append(QString("D: %1").arg(SatNogsTransmitter::getFrequencyRangeText(sat->m_transmitters[i]->m_downlinkLow, sat->m_transmitters[i]->m_downlinkHigh)));
+ else if (sat->m_transmitters[i]->m_downlinkLow > 0)
+ mode.append(QString("D: %1").arg(SatNogsTransmitter::getFrequencyText(sat->m_transmitters[i]->m_downlinkLow)));
+ if (sat->m_transmitters[i]->m_uplinkHigh > 0)
+ mode.append(QString("U: %1").arg(SatNogsTransmitter::getFrequencyRangeText(sat->m_transmitters[i]->m_uplinkLow, sat->m_transmitters[i]->m_uplinkHigh)));
+ else if (sat->m_transmitters[i]->m_uplinkLow > 0)
+ mode.append(QString("U: %1").arg(SatNogsTransmitter::getFrequencyText(sat->m_transmitters[i]->m_uplinkLow)));
+ info.append(mode.join(" "));
+ }
+ }
+ ui->satelliteModes->setText(info.join("\n"));
+}
diff --git a/plugins/feature/satellitetracker/satelliteradiocontroldialog.h b/plugins/feature/satellitetracker/satelliteradiocontroldialog.h
new file mode 100644
index 000000000..7bd92ce3f
--- /dev/null
+++ b/plugins/feature/satellitetracker/satelliteradiocontroldialog.h
@@ -0,0 +1,53 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITERADIOCONTROLDIALOG_H
+#define INCLUDE_FEATURE_SATELLITERADIOCONTROLDIALOG_H
+
+#include
+
+#include "ui_satelliteradiocontroldialog.h"
+#include "satellitetrackersettings.h"
+#include "satellitedevicesettingsgui.h"
+#include "satnogs.h"
+
+class SatelliteRadioControlDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit SatelliteRadioControlDialog(SatelliteTrackerSettings* settings, const QHash& satellites, QWidget* parent = 0);
+ ~SatelliteRadioControlDialog();
+
+ SatelliteTrackerSettings *m_settings;
+
+private:
+ void resizeTable();
+
+private slots:
+ void accept();
+ void on_add_clicked();
+ void on_remove_clicked();
+ void on_satelliteSelect_currentIndexChanged(int index);
+
+private:
+ const QHash& m_satellites;
+ QHash *> m_deviceSettings; // Device settings per sateillite
+ QList m_devSettingsGUIs; // For selected satellite
+ Ui::SatelliteRadioControlDialog* ui;
+};
+
+#endif // INCLUDE_FEATURE_SATELLITERADIOCONTROLDIALOG_H
diff --git a/plugins/feature/satellitetracker/satelliteradiocontroldialog.ui b/plugins/feature/satellitetracker/satelliteradiocontroldialog.ui
new file mode 100644
index 000000000..6a4b87daa
--- /dev/null
+++ b/plugins/feature/satellitetracker/satelliteradiocontroldialog.ui
@@ -0,0 +1,259 @@
+
+
+ SatelliteRadioControlDialog
+
+
+
+ 0
+ 0
+ 955
+ 400
+
+
+
+
+ Liberation Sans
+ 9
+
+
+
+ Qt::PreventContextMenu
+
+
+ Satellite Radio Control
+
+
+
+
+
+
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+
+ Device set
+
+
+ Device set to control
+
+
+
+
+ Preset to load on AOS
+
+
+ Preset to load to device set
+
+
+
+
+ Doppler correction
+
+
+ Channel numbers that will have Doppler correction applied
+
+
+
+
+ Start on AOS
+
+
+ Start acquisition on AOS
+
+
+
+
+ Stop on LOS
+
+
+ Stop acquisition on LOS
+
+
+
+
+ Start/stop file sinks
+
+
+ Start file sinks recording on AOS and stop recording on LOS
+
+
+
+
+ Override frequency (MHz)
+
+
+ Override the center frequency in the preset with a value specified here in MHz.
+This allows a single preset to be shared between different satellites that differ only in frequency.
+
+
+
+
+ AOS command
+
+
+ Command to execute on AOS
+
+
+
+
+ LOS command
+
+
+ Command to execute on LOS
+
+
+
+
+
+
+
+ Satellite modes from SatNOGS
+
+
+ true
+
+
+
+
+
+
+
+
+ Satellite
+
+
+
+
+
+
+
+ 150
+ 0
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+ Add device set control
+
+
+ +
+
+
+
+
+
+
+ Remove device set control
+
+
+ -
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+ Satellite modes
+
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+ satelliteSelect
+ table
+ add
+ remove
+ satelliteModes
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ SatelliteRadioControlDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ SatelliteRadioControlDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/plugins/feature/satellitetracker/satelliteselectiondialog.cpp b/plugins/feature/satellitetracker/satelliteselectiondialog.cpp
new file mode 100644
index 000000000..eb61a8f59
--- /dev/null
+++ b/plugins/feature/satellitetracker/satelliteselectiondialog.cpp
@@ -0,0 +1,281 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "satelliteselectiondialog.h"
+#include "util/units.h"
+
+SatelliteSelectionDialog::SatelliteSelectionDialog(SatelliteTrackerSettings *settings,
+ const QHash& satellites,
+ QWidget* parent) :
+ QDialog(parent),
+ m_settings(settings),
+ m_satellites(satellites),
+ m_satInfo(nullptr),
+ ui(new Ui::SatelliteSelectionDialog)
+{
+ ui->setupUi(this);
+ m_networkManager = new QNetworkAccessManager();
+ connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
+
+ QHashIterator itr(satellites);
+ while (itr.hasNext())
+ {
+ itr.next();
+ QString name = itr.key();
+ SatNogsSatellite *sat = itr.value();
+ // Don't display decayed satellites, or those without TLEs
+ if ((sat->m_status == "alive") || (sat->m_status == ""))
+ {
+ if (sat->m_tle != nullptr)
+ {
+ if (settings->m_satellites.indexOf(name) == -1)
+ ui->availableSats->addItem(name);
+ }
+ else
+ qDebug() << "SatelliteSelectionDialog::SatelliteSelectionDialog: No TLE for " << name;
+ }
+ }
+ for (int i = 0; i < settings->m_satellites.size(); i++)
+ ui->selectedSats->addItem(settings->m_satellites[i]);
+}
+
+SatelliteSelectionDialog::~SatelliteSelectionDialog()
+{
+ delete ui;
+}
+
+void SatelliteSelectionDialog::accept()
+{
+ m_settings->m_satellites.clear();
+ for (int i = 0; i < ui->selectedSats->count(); i++)
+ m_settings->m_satellites.append(ui->selectedSats->item(i)->text());
+ QDialog::accept();
+}
+
+void SatelliteSelectionDialog::on_find_textChanged(const QString &text)
+{
+ QString textTrimmed = text.trimmed();
+ QList items = ui->availableSats->findItems(textTrimmed, Qt::MatchContains);
+ if (items.size() > 0)
+ ui->availableSats->setCurrentItem(items[0]);
+ else
+ {
+ // Try alternative names
+ QHashIterator itr(m_satellites);
+ while (itr.hasNext())
+ {
+ itr.next();
+ SatNogsSatellite *sat = itr.value();
+ if (sat->m_names.indexOf(textTrimmed) != -1)
+ {
+ QList items = ui->availableSats->findItems(sat->m_name, Qt::MatchExactly);
+ if (items.size() > 0)
+ ui->availableSats->setCurrentItem(items[0]);
+ break;
+ }
+ }
+ }
+}
+
+void SatelliteSelectionDialog::on_addSat_clicked()
+{
+ QList items = ui->availableSats->selectedItems();
+ for (int i = 0; i < items.size(); i++)
+ {
+ ui->selectedSats->addItem(items[i]->text());
+ delete items[i];
+ }
+}
+
+void SatelliteSelectionDialog::on_removeSat_clicked()
+{
+ QList items = ui->selectedSats->selectedItems();
+ for (int i = 0; i < items.size(); i++)
+ {
+ ui->availableSats->addItem(items[i]->text());
+ delete items[i];
+ }
+}
+
+void SatelliteSelectionDialog::on_moveUp_clicked()
+{
+ QList items = ui->selectedSats->selectedItems();
+ for (int i = 0; i < items.size(); i++)
+ {
+ int row = ui->selectedSats->row(items[i]);
+ if (row > 0)
+ {
+ QListWidgetItem *item = ui->selectedSats->takeItem(row);
+ ui->selectedSats->insertItem(row - 1, item);
+ ui->selectedSats->setCurrentItem(item);
+ }
+ }
+}
+
+void SatelliteSelectionDialog::on_moveDown_clicked()
+{
+ QList items = ui->selectedSats->selectedItems();
+ for (int i = items.size() - 1; i >= 0; i--)
+ {
+ int row = ui->selectedSats->row(items[i]);
+ if (row < ui->selectedSats->count() - 1)
+ {
+ QListWidgetItem *item = ui->selectedSats->takeItem(row);
+ ui->selectedSats->insertItem(row + 1, item);
+ ui->selectedSats->setCurrentItem(item);
+ }
+ }
+}
+
+void SatelliteSelectionDialog::on_availableSats_itemDoubleClicked(QListWidgetItem *item)
+{
+ ui->selectedSats->addItem(item->text());
+ delete item;
+}
+
+void SatelliteSelectionDialog::on_selectedSats_itemDoubleClicked(QListWidgetItem *item)
+{
+ ui->availableSats->addItem(item->text());
+ delete item;
+}
+
+void SatelliteSelectionDialog::on_availableSats_itemSelectionChanged()
+{
+ QList items = ui->availableSats->selectedItems();
+ if (items.size() > 0)
+ {
+ ui->selectedSats->selectionModel()->clear();
+ displaySatInfo(items[0]->text());
+ }
+}
+
+void SatelliteSelectionDialog::on_selectedSats_itemSelectionChanged()
+{
+ QList items = ui->selectedSats->selectedItems();
+ if (items.size() > 0)
+ {
+ ui->availableSats->selectionModel()->clear();
+ displaySatInfo(items[0]->text());
+ }
+}
+
+// Display information about the satellite from the SatNOGS database
+void SatelliteSelectionDialog::displaySatInfo(const QString& name)
+{
+ SatNogsSatellite *sat = m_satellites[name];
+ m_satInfo = sat;
+ QStringList info;
+ info.append(QString("Name: %1").arg(sat->m_name));
+ if (sat->m_names.size() > 0)
+ info.append(QString("Alternative names: %1").arg(sat->m_names.join(" ")));
+ info.append(QString("NORAD ID: %1").arg(sat->m_noradCatId));
+ if (sat->m_launched.isValid())
+ info.append(QString("Launched: %1").arg(sat->m_launched.toString()));
+ if (sat->m_deployed.isValid())
+ info.append(QString("Deployed: %1").arg(sat->m_deployed.toString()));
+ if (sat->m_decayed.isValid())
+ info.append(QString("Decayed: %1").arg(sat->m_decayed.toString()));
+ ui->openSatelliteWebsite->setEnabled(!sat->m_website.isEmpty());
+ if (!sat->m_operator.isEmpty() && sat->m_operator != "None")
+ info.append(QString("Operator: %1").arg(sat->m_operator));
+ if (!sat->m_countries.isEmpty())
+ info.append(QString("Countries: %1").arg(sat->m_countries));
+ if (sat->m_transmitters.size() > 0)
+ info.append("Modes:");
+ for (int i = 0; i < sat->m_transmitters.size(); i++)
+ {
+ if (sat->m_transmitters[i]->m_status != "invalid")
+ {
+ QStringList mode;
+ mode.append(" ");
+ mode.append(sat->m_transmitters[i]->m_description);
+ if (sat->m_transmitters[i]->m_downlinkHigh > 0)
+ mode.append(QString("D: %1").arg(SatNogsTransmitter::getFrequencyRangeText(sat->m_transmitters[i]->m_downlinkLow, sat->m_transmitters[i]->m_downlinkHigh)));
+ else if (sat->m_transmitters[i]->m_downlinkLow > 0)
+ mode.append(QString("D: %1").arg(SatNogsTransmitter::getFrequencyText(sat->m_transmitters[i]->m_downlinkLow)));
+ if (sat->m_transmitters[i]->m_uplinkHigh > 0)
+ mode.append(QString("U: %1").arg(SatNogsTransmitter::getFrequencyRangeText(sat->m_transmitters[i]->m_uplinkLow, sat->m_transmitters[i]->m_uplinkHigh)));
+ else if (sat->m_transmitters[i]->m_uplinkLow > 0)
+ mode.append(QString("U: %1").arg(SatNogsTransmitter::getFrequencyText(sat->m_transmitters[i]->m_uplinkLow)));
+ info.append(mode.join(" "));
+ }
+ }
+ if (sat->m_tle != nullptr)
+ {
+ info.append("Orbit:");
+ Tle tle = Tle(sat->m_tle->m_tle0.toStdString(),
+ sat->m_tle->m_tle1.toStdString(),
+ sat->m_tle->m_tle2.toStdString());
+ OrbitalElements ele(tle);
+ info.append(QString(" Period: %1 mins").arg(ele.Period()));
+ info.append(QString(" Inclination: %1%2").arg(Units::radiansToDegrees(ele.Inclination())).arg(QChar(0xb0)));
+ info.append(QString(" Eccentricity: %1").arg(ele.Eccentricity()));
+ }
+
+ ui->satInfo->setText(info.join("\n"));
+ if (!sat->m_image.isEmpty())
+ m_networkManager->get(QNetworkRequest(QUrl(sat->m_image)));
+ else
+ ui->satImage->setPixmap(QPixmap());
+}
+
+// Open the Satellite's webpage
+void SatelliteSelectionDialog::on_openSatelliteWebsite_clicked()
+{
+ if ((m_satInfo != nullptr) && (!m_satInfo->m_website.isEmpty()))
+ QDesktopServices::openUrl(QUrl(m_satInfo->m_website));
+}
+
+// Open SatNOGS observations website for the selected satellite
+void SatelliteSelectionDialog::on_openSatNogsObservations_clicked()
+{
+ if (m_satInfo != nullptr)
+ QDesktopServices::openUrl(QUrl(QString("https://network.satnogs.org/observations/?norad=%1").arg(m_satInfo->m_noradCatId)));
+}
+
+void SatelliteSelectionDialog::networkManagerFinished(QNetworkReply *reply)
+{
+ QNetworkReply::NetworkError replyError = reply->error();
+
+ if (replyError)
+ {
+ qWarning() << "SatelliteSelectionDialog::networkManagerFinished:"
+ << " error(" << (int) replyError
+ << "): " << replyError
+ << ": " << reply->errorString();
+ }
+ else
+ {
+ // Read image data and display it
+ QByteArray imageData = reply->readAll();
+ QPixmap pixmap;
+ if (pixmap.loadFromData(imageData))
+ ui->satImage->setPixmap(pixmap.scaled( ui->satImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
+ else
+ qDebug() << "SatelliteSelectionDialog::networkManagerFinished: Failed to load pixmap from image data";
+ }
+
+ reply->deleteLater();
+}
diff --git a/plugins/feature/satellitetracker/satelliteselectiondialog.h b/plugins/feature/satellitetracker/satelliteselectiondialog.h
new file mode 100644
index 000000000..a6973b615
--- /dev/null
+++ b/plugins/feature/satellitetracker/satelliteselectiondialog.h
@@ -0,0 +1,65 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_SATELLITESELECTIONDIALOG_H
+#define INCLUDE_SATELLITESELECTIONDIALOG_H
+
+#include
+#include
+
+#include "ui_satelliteselectiondialog.h"
+#include "satellitetrackersettings.h"
+#include "satnogs.h"
+
+class QNetworkAccessManager;
+class QNetworkReply;
+
+class SatelliteSelectionDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit SatelliteSelectionDialog(SatelliteTrackerSettings* settings, const QHash& satellites, QWidget* parent = 0);
+ ~SatelliteSelectionDialog();
+
+ SatelliteTrackerSettings *m_settings;
+
+private:
+ void displaySatInfo(const QString& name);
+
+private slots:
+ void accept();
+ void on_find_textChanged(const QString &text);
+ void on_addSat_clicked();
+ void on_removeSat_clicked();
+ void on_moveUp_clicked();
+ void on_moveDown_clicked();
+ void on_availableSats_itemDoubleClicked(QListWidgetItem *item);
+ void on_selectedSats_itemDoubleClicked(QListWidgetItem *item);
+ void on_availableSats_itemSelectionChanged();
+ void on_selectedSats_itemSelectionChanged();
+ void on_openSatelliteWebsite_clicked();
+ void on_openSatNogsObservations_clicked();
+ void networkManagerFinished(QNetworkReply *reply);
+
+private:
+ QNetworkAccessManager *m_networkManager;
+ const QHash& m_satellites;
+ SatNogsSatellite *m_satInfo;
+ Ui::SatelliteSelectionDialog* ui;
+};
+
+#endif // INCLUDE_SATELLITESELECTIONDIALOG_H
diff --git a/plugins/feature/satellitetracker/satelliteselectiondialog.ui b/plugins/feature/satellitetracker/satelliteselectiondialog.ui
new file mode 100644
index 000000000..13f997d3a
--- /dev/null
+++ b/plugins/feature/satellitetracker/satelliteselectiondialog.ui
@@ -0,0 +1,357 @@
+
+
+ SatelliteSelectionDialog
+
+
+
+ 0
+ 0
+ 696
+ 561
+
+
+
+
+ Liberation Sans
+ 9
+
+
+
+ Select satellites to track
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Satellite selection
+
+
+
+
+
+
+
+ Available satellites
+
+
+
+
+
+
+ Satellites to track
+
+
+
+
+
+
+
+
+
+
+ List of available satellites. Double click or press right arrow to move to selected list.
+
+
+ QAbstractItemView::ExtendedSelection
+
+
+ true
+
+
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+ Add satellite to selected list
+
+
+
+
+
+
+ :/arrow_left.png:/arrow_left.png
+
+
+
+
+
+
+ Remove satellite from selected list
+
+
+
+
+
+
+ :/arrow_right.png:/arrow_right.png
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+ List of selected satellites. Double click or press left arrow to move to available list. Order according to priority for automatic selection on AOS.
+
+
+ QAbstractItemView::ExtendedSelection
+
+
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+ Move satellite up in list
+
+
+
+
+
+
+ :/arrow_up.png:/arrow_up.png
+
+
+
+
+
+
+ Move satellite down in list
+
+
+
+
+
+
+ :/arrow_down.png:/arrow_down.png
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Find
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 150
+ 0
+
+
+
+ Enter name of satellite to find in the available satellites list
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+ Satellite information
+
+
+
+
+
+ Information from SatNOGS about the selected satellite
+
+
+ true
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Image of satellite
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+ Display website for the satellite
+
+
+ Satellite website
+
+
+
+
+
+
+ Display SatNOGS observations of the satellite
+
+
+ SatNOGS observations
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ SatelliteSelectionDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ SatelliteSelectionDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/plugins/feature/satellitetracker/satellitetracker.cpp b/plugins/feature/satellitetracker/satellitetracker.cpp
new file mode 100644
index 000000000..a57a576ea
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetracker.cpp
@@ -0,0 +1,883 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+
+#include "SWGFeatureSettings.h"
+#include "SWGFeatureReport.h"
+#include "SWGFeatureActions.h"
+#include "SWGDeviceState.h"
+
+#include "dsp/dspengine.h"
+#include "util/httpdownloadmanager.h"
+
+#include "satellitetrackerworker.h"
+#include "satellitetracker.h"
+
+MESSAGE_CLASS_DEFINITION(SatelliteTracker::MsgConfigureSatelliteTracker, Message)
+MESSAGE_CLASS_DEFINITION(SatelliteTracker::MsgStartStop, Message)
+MESSAGE_CLASS_DEFINITION(SatelliteTracker::MsgUpdateSatData, Message)
+MESSAGE_CLASS_DEFINITION(SatelliteTracker::MsgSatData, Message)
+
+const char* const SatelliteTracker::m_featureIdURI = "sdrangel.feature.satellitetracker";
+const char* const SatelliteTracker::m_featureId = "SatelliteTracker";
+
+SatelliteTracker::SatelliteTracker(WebAPIAdapterInterface *webAPIAdapterInterface) :
+ Feature(m_featureIdURI, webAPIAdapterInterface),
+ m_updatingSatData(false),
+ m_tleIndex(0),
+ m_firstUpdateSatData(true)
+{
+ qDebug("SatelliteTracker::SatelliteTracker: webAPIAdapterInterface: %p", webAPIAdapterInterface);
+ setObjectName(m_featureId);
+ m_worker = new SatelliteTrackerWorker(this, webAPIAdapterInterface);
+ m_state = StIdle;
+ m_errorMessage = "SatelliteTracker error";
+ m_networkManager = new QNetworkAccessManager();
+ connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
+ connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &SatelliteTracker::downloadFinished);
+
+ if (!readSatData())
+ updateSatData();
+}
+
+SatelliteTracker::~SatelliteTracker()
+{
+ if (m_worker->isRunning()) {
+ stop();
+ }
+
+ delete m_worker;
+}
+
+void SatelliteTracker::start()
+{
+ qDebug("SatelliteTracker::start");
+
+ m_worker->reset();
+ m_worker->setMessageQueueToFeature(getInputMessageQueue());
+ m_worker->setMessageQueueToGUI(getMessageQueueToGUI());
+ bool ok = m_worker->startWork();
+ m_state = ok ? StRunning : StError;
+ m_thread.start();
+
+ m_worker->getInputMessageQueue()->push(SatelliteTrackerWorker::MsgConfigureSatelliteTrackerWorker::create(m_settings, true));
+ m_worker->getInputMessageQueue()->push(MsgSatData::create(m_satellites));
+}
+
+void SatelliteTracker::stop()
+{
+ qDebug("SatelliteTracker::stop");
+ m_worker->stopWork();
+ m_state = StIdle;
+ m_thread.quit();
+ m_thread.wait();
+}
+
+bool SatelliteTracker::handleMessage(const Message& cmd)
+{
+ if (MsgConfigureSatelliteTracker::match(cmd))
+ {
+ MsgConfigureSatelliteTracker& cfg = (MsgConfigureSatelliteTracker&) cmd;
+ qDebug() << "SatelliteTracker::handleMessage: MsgConfigureSatelliteTracker";
+ applySettings(cfg.getSettings(), cfg.getForce());
+
+ return true;
+ }
+ else if (MsgStartStop::match(cmd))
+ {
+ MsgStartStop& cfg = (MsgStartStop&) cmd;
+ qDebug() << "SatelliteTracker::handleMessage: MsgStartStop: start:" << cfg.getStartStop();
+
+ if (cfg.getStartStop()) {
+ start();
+ } else {
+ stop();
+ }
+
+ return true;
+ }
+ else if (MsgUpdateSatData::match(cmd))
+ {
+ // When the GUI first opens, it will make an initial request to update the sats
+ // In the first instance, just return the data we've read
+ if (m_firstUpdateSatData && (m_satellites.size() > 0))
+ {
+ if (m_guiMessageQueue)
+ m_guiMessageQueue->push(MsgSatData::create(m_satellites));
+ m_firstUpdateSatData = false;
+ }
+ else
+ updateSatData();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+QByteArray SatelliteTracker::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool SatelliteTracker::deserialize(const QByteArray& data)
+{
+ if (m_settings.deserialize(data))
+ {
+ MsgConfigureSatelliteTracker *msg = MsgConfigureSatelliteTracker::create(m_settings, true);
+ m_inputMessageQueue.push(msg);
+ return true;
+ }
+ else
+ {
+ m_settings.resetToDefaults();
+ MsgConfigureSatelliteTracker *msg = MsgConfigureSatelliteTracker::create(m_settings, true);
+ m_inputMessageQueue.push(msg);
+ return false;
+ }
+}
+
+void SatelliteTracker::applySettings(const SatelliteTrackerSettings& settings, bool force)
+{
+ bool tlesChanged = false;
+
+ qDebug() << "SatelliteTracker::applySettings:"
+ << " m_latitude: " << settings.m_latitude
+ << " m_longitude: " << settings.m_longitude
+ << " m_heightAboveSeaLevel: " << settings.m_heightAboveSeaLevel
+ << " m_target: " << settings.m_target
+ << " m_satellites: " << settings.m_satellites
+ << " m_tles: " << settings.m_tles
+ << " m_dateTime: " << settings.m_dateTime
+ << " m_minAOSElevation: " << settings.m_minAOSElevation
+ << " m_minPassElevation: " << settings.m_minPassElevation
+ << " m_azElUnits: " << settings.m_azElUnits
+ << " m_groundTrackPoints: " << settings.m_groundTrackPoints
+ << " m_dateFormat: " << settings.m_dateFormat
+ << " m_utc: " << settings.m_utc
+ << " m_updatePeriod: " << settings.m_updatePeriod
+ << " m_dopplerPeriod: " << settings.m_dopplerPeriod
+ << " m_defaultFrequency: " << settings.m_defaultFrequency
+ << " m_drawOnMap: " << settings.m_drawOnMap
+ << " m_autoTarget: " << settings.m_autoTarget
+ << " m_aosSpeech: " << settings.m_aosSpeech
+ << " m_losSpeech: " << settings.m_losSpeech
+ << " m_aosCommand: " << settings.m_aosCommand
+ << " m_losCommand: " << settings.m_losCommand
+ << " m_predictionPeriod: " << settings.m_predictionPeriod
+ << " m_passStartTime: " << settings.m_passStartTime
+ << " m_passFinishTime: " << settings.m_passFinishTime
+ << " m_deviceSettings: " << settings.m_deviceSettings
+ << " m_title: " << settings.m_title
+ << " m_rgbColor: " << settings.m_rgbColor
+ << " m_useReverseAPI: " << settings.m_useReverseAPI
+ << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
+ << " m_reverseAPIPort: " << settings.m_reverseAPIPort
+ << " m_reverseAPIFeatureSetIndex: " << settings.m_reverseAPIFeatureSetIndex
+ << " m_reverseAPIFeatureIndex: " << settings.m_reverseAPIFeatureIndex
+ << " force: " << force;
+
+ QList reverseAPIKeys;
+
+ if ((m_settings.m_latitude != settings.m_latitude) || force) {
+ reverseAPIKeys.append("latitude");
+ }
+ if ((m_settings.m_longitude != settings.m_longitude) || force) {
+ reverseAPIKeys.append("longitude");
+ }
+ if ((m_settings.m_heightAboveSeaLevel != settings.m_heightAboveSeaLevel) || force) {
+ reverseAPIKeys.append("heightAboveSeaLevel");
+ }
+ if ((m_settings.m_target != settings.m_target) || force) {
+ reverseAPIKeys.append("target");
+ }
+ if ((m_settings.m_satellites != settings.m_satellites) || force) {
+ reverseAPIKeys.append("satellites");
+ }
+ if ((m_settings.m_tles != settings.m_tles) || force) {
+ tlesChanged = true;
+ reverseAPIKeys.append("tles");
+ }
+ if ((m_settings.m_dateTime != settings.m_dateTime) || force) {
+ reverseAPIKeys.append("dateTime");
+ }
+ if ((m_settings.m_minAOSElevation != settings.m_minAOSElevation) || force) {
+ reverseAPIKeys.append("minAOSElevation");
+ }
+ if ((m_settings.m_minPassElevation != settings.m_minPassElevation) || force) {
+ reverseAPIKeys.append("minPassElevation");
+ }
+ if ((m_settings.m_azElUnits != settings.m_azElUnits) || force) {
+ reverseAPIKeys.append("azElUnits");
+ }
+ if ((m_settings.m_groundTrackPoints != settings.m_groundTrackPoints) || force) {
+ reverseAPIKeys.append("groundTrackPoints");
+ }
+ if ((m_settings.m_dateFormat != settings.m_dateFormat) || force) {
+ reverseAPIKeys.append("dateFormat");
+ }
+ if ((m_settings.m_utc != settings.m_utc) || force) {
+ reverseAPIKeys.append("utc");
+ }
+ if ((m_settings.m_updatePeriod != settings.m_updatePeriod) || force) {
+ reverseAPIKeys.append("updatePeriod");
+ }
+ if ((m_settings.m_dopplerPeriod != settings.m_dopplerPeriod) || force) {
+ reverseAPIKeys.append("dopplerPeriod");
+ }
+ if ((m_settings.m_defaultFrequency != settings.m_defaultFrequency) || force) {
+ reverseAPIKeys.append("defaultFrequency");
+ }
+ if ((m_settings.m_drawOnMap != settings.m_drawOnMap) || force) {
+ reverseAPIKeys.append("drawOnMap");
+ }
+ if ((m_settings.m_autoTarget != settings.m_autoTarget) || force) {
+ reverseAPIKeys.append("autoTarget");
+ }
+ if ((m_settings.m_aosSpeech != settings.m_aosSpeech) || force) {
+ reverseAPIKeys.append("aosSpeech");
+ }
+ if ((m_settings.m_losSpeech != settings.m_losSpeech) || force) {
+ reverseAPIKeys.append("losSpeech");
+ }
+ if ((m_settings.m_aosCommand != settings.m_aosCommand) || force) {
+ reverseAPIKeys.append("aosCommand");
+ }
+ if ((m_settings.m_losCommand != settings.m_losCommand) || force) {
+ reverseAPIKeys.append("losCommand");
+ }
+ if ((m_settings.m_predictionPeriod != settings.m_predictionPeriod) || force) {
+ reverseAPIKeys.append("predictionPeriod");
+ }
+ if ((m_settings.m_passStartTime != settings.m_passStartTime) || force) {
+ reverseAPIKeys.append("passStartTime");
+ }
+ if ((m_settings.m_passFinishTime != settings.m_passFinishTime) || force) {
+ reverseAPIKeys.append("passFinishTime");
+ }
+ if ((m_settings.m_deviceSettings != settings.m_deviceSettings) || force) {
+ reverseAPIKeys.append("deviceSettings");
+ }
+ if ((m_settings.m_title != settings.m_title) || force) {
+ reverseAPIKeys.append("title");
+ }
+ if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) {
+ reverseAPIKeys.append("rgbColor");
+ }
+
+ SatelliteTrackerWorker::MsgConfigureSatelliteTrackerWorker *msg = SatelliteTrackerWorker::MsgConfigureSatelliteTrackerWorker::create(
+ settings, force
+ );
+ m_worker->getInputMessageQueue()->push(msg);
+
+ if (settings.m_useReverseAPI)
+ {
+ bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
+ (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
+ (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
+ (m_settings.m_reverseAPIFeatureSetIndex != settings.m_reverseAPIFeatureSetIndex) ||
+ (m_settings.m_reverseAPIFeatureIndex != settings.m_reverseAPIFeatureIndex);
+ webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
+ }
+
+ m_settings = settings;
+
+ if (tlesChanged)
+ {
+ // Do we already have the TLE files, or do we need to download them?
+ bool existing = true;
+ for (int i = 0; i < m_settings.m_tles.size(); i++)
+ {
+ QFile tlesFile(tleURLToFilename(m_settings.m_tles[i]));
+ if (!tlesFile.exists())
+ {
+ existing = false;
+ break;
+ }
+ }
+ if (existing)
+ readSatData();
+ else
+ updateSatData();
+ }
+}
+
+int SatelliteTracker::webapiRun(bool run,
+ SWGSDRangel::SWGDeviceState& response,
+ QString& errorMessage)
+{
+ (void) errorMessage;
+ getFeatureStateStr(*response.getState());
+ MsgStartStop *msg = MsgStartStop::create(run);
+ getInputMessageQueue()->push(msg);
+ return 202;
+}
+
+int SatelliteTracker::webapiSettingsGet(
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage)
+{
+ (void) errorMessage;
+ response.setSatelliteTrackerSettings(new SWGSDRangel::SWGSatelliteTrackerSettings());
+ response.getSatelliteTrackerSettings()->init();
+ webapiFormatFeatureSettings(response, m_settings);
+ return 200;
+}
+
+int SatelliteTracker::webapiSettingsPutPatch(
+ bool force,
+ const QStringList& featureSettingsKeys,
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage)
+{
+ (void) errorMessage;
+ SatelliteTrackerSettings settings = m_settings;
+ webapiUpdateFeatureSettings(settings, featureSettingsKeys, response);
+
+ MsgConfigureSatelliteTracker *msg = MsgConfigureSatelliteTracker::create(settings, force);
+ m_inputMessageQueue.push(msg);
+
+ qDebug("SatelliteTracker::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
+ if (m_guiMessageQueue) // forward to GUI if any
+ {
+ MsgConfigureSatelliteTracker *msgToGUI = MsgConfigureSatelliteTracker::create(settings, force);
+ m_guiMessageQueue->push(msgToGUI);
+ }
+
+ webapiFormatFeatureSettings(response, settings);
+ return 200;
+}
+
+static QList *convertStringListToPtrs(QStringList listIn)
+{
+ QList *listOut = new QList();
+
+ for (int i = 0; i < listIn.size(); i++)
+ listOut->append(new QString(listIn[i]));
+
+ return listOut;
+}
+
+static QStringList convertPtrsToStringList(QList *listIn)
+{
+ QStringList listOut;
+
+ for (int i = 0; i < listIn->size(); i++)
+ listOut.append(*listIn->at(i));
+
+ return listOut;
+}
+
+void SatelliteTracker::webapiFormatFeatureSettings(
+ SWGSDRangel::SWGFeatureSettings& response,
+ const SatelliteTrackerSettings& settings)
+{
+ response.getSatelliteTrackerSettings()->setLatitude(settings.m_latitude);
+ response.getSatelliteTrackerSettings()->setLongitude(settings.m_longitude);
+ response.getSatelliteTrackerSettings()->setHeightAboveSeaLevel(settings.m_heightAboveSeaLevel);
+ response.getSatelliteTrackerSettings()->setTarget(new QString(settings.m_target));
+ response.getSatelliteTrackerSettings()->setSatellites(convertStringListToPtrs(settings.m_satellites));
+ response.getSatelliteTrackerSettings()->setTles(convertStringListToPtrs(settings.m_tles));
+ response.getSatelliteTrackerSettings()->setDateTime(new QString(settings.m_dateTime));
+ response.getSatelliteTrackerSettings()->setMinAosElevation(settings.m_minAOSElevation);
+ response.getSatelliteTrackerSettings()->setMinPassElevation(settings.m_minPassElevation);
+ response.getSatelliteTrackerSettings()->setAzElUnits((int)settings.m_azElUnits);
+ response.getSatelliteTrackerSettings()->setGroundTrackPoints(settings.m_groundTrackPoints);
+ response.getSatelliteTrackerSettings()->setDateFormat(new QString(settings.m_dateFormat));
+ response.getSatelliteTrackerSettings()->setUtc(settings.m_utc);
+ response.getSatelliteTrackerSettings()->setUpdatePeriod(settings.m_updatePeriod);
+ response.getSatelliteTrackerSettings()->setDopplerPeriod(settings.m_dopplerPeriod);
+ response.getSatelliteTrackerSettings()->setDefaultFrequency(settings.m_defaultFrequency);
+ response.getSatelliteTrackerSettings()->setDrawOnMap(settings.m_drawOnMap);
+ response.getSatelliteTrackerSettings()->setAutoTarget(settings.m_autoTarget);
+ response.getSatelliteTrackerSettings()->setAosSpeech(new QString(settings.m_aosSpeech));
+ response.getSatelliteTrackerSettings()->setLosSpeech(new QString(settings.m_losSpeech));
+ response.getSatelliteTrackerSettings()->setAosCommand(new QString(settings.m_aosCommand));
+ response.getSatelliteTrackerSettings()->setLosCommand(new QString(settings.m_losCommand));
+ response.getSatelliteTrackerSettings()->setPredictionPeriod(settings.m_predictionPeriod);
+ response.getSatelliteTrackerSettings()->setPassStartTime(new QString(settings.m_passStartTime.toString()));
+ response.getSatelliteTrackerSettings()->setPassFinishTime(new QString(settings.m_passFinishTime.toString()));
+
+ if (response.getSatelliteTrackerSettings()->getTitle()) {
+ *response.getSatelliteTrackerSettings()->getTitle() = settings.m_title;
+ } else {
+ response.getSatelliteTrackerSettings()->setTitle(new QString(settings.m_title));
+ }
+
+ response.getSatelliteTrackerSettings()->setRgbColor(settings.m_rgbColor);
+ response.getSatelliteTrackerSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
+
+ if (response.getSatelliteTrackerSettings()->getReverseApiAddress()) {
+ *response.getSatelliteTrackerSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
+ } else {
+ response.getSatelliteTrackerSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
+ }
+
+ response.getSatelliteTrackerSettings()->setReverseApiPort(settings.m_reverseAPIPort);
+ response.getSatelliteTrackerSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIFeatureSetIndex);
+ response.getSatelliteTrackerSettings()->setReverseApiChannelIndex(settings.m_reverseAPIFeatureIndex);
+}
+
+void SatelliteTracker::webapiUpdateFeatureSettings(
+ SatelliteTrackerSettings& settings,
+ const QStringList& featureSettingsKeys,
+ SWGSDRangel::SWGFeatureSettings& response)
+{
+ if (featureSettingsKeys.contains("latitude")) {
+ settings.m_latitude = response.getSatelliteTrackerSettings()->getLatitude();
+ }
+ if (featureSettingsKeys.contains("longitude")) {
+ settings.m_longitude = response.getSatelliteTrackerSettings()->getLongitude();
+ }
+ if (featureSettingsKeys.contains("heightAboveSeaLevel")) {
+ settings.m_heightAboveSeaLevel = response.getSatelliteTrackerSettings()->getHeightAboveSeaLevel();
+ }
+ if (featureSettingsKeys.contains("target")) {
+ settings.m_target = *response.getSatelliteTrackerSettings()->getTarget();
+ }
+ if (featureSettingsKeys.contains("satellites")) {
+ settings.m_satellites = convertPtrsToStringList(response.getSatelliteTrackerSettings()->getSatellites());
+ }
+ if (featureSettingsKeys.contains("tles")) {
+ settings.m_tles = convertPtrsToStringList(response.getSatelliteTrackerSettings()->getTles());
+ }
+ if (featureSettingsKeys.contains("dateTime")) {
+ settings.m_dateTime = *response.getSatelliteTrackerSettings()->getDateTime();
+ }
+ if (featureSettingsKeys.contains("minAOSElevation")) {
+ settings.m_minAOSElevation = response.getSatelliteTrackerSettings()->getMinAosElevation();
+ }
+ if (featureSettingsKeys.contains("minPassElevation")) {
+ settings.m_minPassElevation = response.getSatelliteTrackerSettings()->getMinPassElevation();
+ }
+ if (featureSettingsKeys.contains("azElUnits")) {
+ settings.m_azElUnits = (SatelliteTrackerSettings::AzElUnits)response.getSatelliteTrackerSettings()->getAzElUnits();
+ }
+ if (featureSettingsKeys.contains("groundTrackPoints")) {
+ settings.m_groundTrackPoints = response.getSatelliteTrackerSettings()->getGroundTrackPoints();
+ }
+ if (featureSettingsKeys.contains("dateFormat")) {
+ settings.m_dateFormat = *response.getSatelliteTrackerSettings()->getDateFormat();
+ }
+ if (featureSettingsKeys.contains("utc")) {
+ settings.m_utc = response.getSatelliteTrackerSettings()->getUtc() != 0;
+ }
+ if (featureSettingsKeys.contains("updatePeriod")) {
+ settings.m_updatePeriod = response.getSatelliteTrackerSettings()->getUpdatePeriod();
+ }
+ if (featureSettingsKeys.contains("dopplerPeriod")) {
+ settings.m_dopplerPeriod = response.getSatelliteTrackerSettings()->getDopplerPeriod();
+ }
+ if (featureSettingsKeys.contains("defaultFrequency")) {
+ settings.m_defaultFrequency = response.getSatelliteTrackerSettings()->getDefaultFrequency();
+ }
+ if (featureSettingsKeys.contains("drawOnMap")) {
+ settings.m_drawOnMap = response.getSatelliteTrackerSettings()->getDrawOnMap() != 0;
+ }
+ if (featureSettingsKeys.contains("autoTarget")) {
+ settings.m_autoTarget = response.getSatelliteTrackerSettings()->getAutoTarget() != 0;
+ }
+ if (featureSettingsKeys.contains("aosSpeech")) {
+ settings.m_aosSpeech = *response.getSatelliteTrackerSettings()->getAosSpeech();
+ }
+ if (featureSettingsKeys.contains("losSpeech")) {
+ settings.m_losSpeech = *response.getSatelliteTrackerSettings()->getLosSpeech();
+ }
+ if (featureSettingsKeys.contains("aosCommand")) {
+ settings.m_aosCommand = *response.getSatelliteTrackerSettings()->getAosCommand();
+ }
+ if (featureSettingsKeys.contains("losCommand")) {
+ settings.m_losCommand = *response.getSatelliteTrackerSettings()->getLosCommand();
+ }
+ if (featureSettingsKeys.contains("predictionPeriod")) {
+ settings.m_predictionPeriod = response.getSatelliteTrackerSettings()->getPredictionPeriod();
+ }
+ if (featureSettingsKeys.contains("passStartTime")) {
+ settings.m_passStartTime = QTime::fromString(*response.getSatelliteTrackerSettings()->getPassStartTime());
+ }
+ if (featureSettingsKeys.contains("passFinishTime")) {
+ settings.m_passFinishTime = QTime::fromString(*response.getSatelliteTrackerSettings()->getPassFinishTime());
+ }
+ if (featureSettingsKeys.contains("title")) {
+ settings.m_title = *response.getSatelliteTrackerSettings()->getTitle();
+ }
+ if (featureSettingsKeys.contains("rgbColor")) {
+ settings.m_rgbColor = response.getSatelliteTrackerSettings()->getRgbColor();
+ }
+ if (featureSettingsKeys.contains("useReverseAPI")) {
+ settings.m_useReverseAPI = response.getSatelliteTrackerSettings()->getUseReverseApi() != 0;
+ }
+ if (featureSettingsKeys.contains("reverseAPIAddress")) {
+ settings.m_reverseAPIAddress = *response.getSatelliteTrackerSettings()->getReverseApiAddress();
+ }
+ if (featureSettingsKeys.contains("reverseAPIPort")) {
+ settings.m_reverseAPIPort = response.getSatelliteTrackerSettings()->getReverseApiPort();
+ }
+ if (featureSettingsKeys.contains("reverseAPIDeviceIndex")) {
+ settings.m_reverseAPIFeatureSetIndex = response.getSatelliteTrackerSettings()->getReverseApiDeviceIndex();
+ }
+ if (featureSettingsKeys.contains("reverseAPIChannelIndex")) {
+ settings.m_reverseAPIFeatureIndex = response.getSatelliteTrackerSettings()->getReverseApiChannelIndex();
+ }
+}
+
+void SatelliteTracker::webapiReverseSendSettings(QList& featureSettingsKeys, const SatelliteTrackerSettings& settings, bool force)
+{
+ SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings();
+ // swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet());
+ // swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex());
+ swgFeatureSettings->setFeatureType(new QString("SatelliteTracker"));
+ swgFeatureSettings->setSatelliteTrackerSettings(new SWGSDRangel::SWGSatelliteTrackerSettings());
+ SWGSDRangel::SWGSatelliteTrackerSettings *swgSatelliteTrackerSettings = swgFeatureSettings->getSatelliteTrackerSettings();
+
+ // transfer data that has been modified. When force is on transfer all data except reverse API data
+
+ if (featureSettingsKeys.contains("latitude") || force) {
+ swgSatelliteTrackerSettings->setLatitude(settings.m_latitude);
+ }
+ if (featureSettingsKeys.contains("longitude") || force) {
+ swgSatelliteTrackerSettings->setLongitude(settings.m_longitude);
+ }
+ if (featureSettingsKeys.contains("heightAboveSeaLevel") || force) {
+ swgSatelliteTrackerSettings->setHeightAboveSeaLevel(settings.m_heightAboveSeaLevel);
+ }
+ if (featureSettingsKeys.contains("target") || force) {
+ swgSatelliteTrackerSettings->setTarget(new QString(settings.m_target));
+ }
+ if (featureSettingsKeys.contains("satellites") || force) {
+ swgSatelliteTrackerSettings->setSatellites(convertStringListToPtrs(settings.m_satellites));
+ }
+ if (featureSettingsKeys.contains("tles") || force) {
+ swgSatelliteTrackerSettings->setTles(convertStringListToPtrs(settings.m_satellites));
+ }
+ if (featureSettingsKeys.contains("dateTime") || force) {
+ swgSatelliteTrackerSettings->setDateTime(new QString(settings.m_dateTime));
+ }
+ if (featureSettingsKeys.contains("minAOSElevation") || force) {
+ swgSatelliteTrackerSettings->setMinAosElevation(settings.m_minAOSElevation);
+ }
+ if (featureSettingsKeys.contains("minPassElevation") || force) {
+ swgSatelliteTrackerSettings->setMinPassElevation(settings.m_minPassElevation);
+ }
+ if (featureSettingsKeys.contains("azElUnits") || force) {
+ swgSatelliteTrackerSettings->setAzElUnits((int)settings.m_azElUnits);
+ }
+ if (featureSettingsKeys.contains("groundTrackPoints") || force) {
+ swgSatelliteTrackerSettings->setGroundTrackPoints(settings.m_groundTrackPoints);
+ }
+ if (featureSettingsKeys.contains("dateFormat") || force) {
+ swgSatelliteTrackerSettings->setDateFormat(new QString(settings.m_dateFormat));
+ }
+ if (featureSettingsKeys.contains("utc") || force) {
+ swgSatelliteTrackerSettings->setUtc(settings.m_utc);
+ }
+ if (featureSettingsKeys.contains("updatePeriod") || force) {
+ swgSatelliteTrackerSettings->setUpdatePeriod(settings.m_updatePeriod);
+ }
+ if (featureSettingsKeys.contains("dopplerPeriod") || force) {
+ swgSatelliteTrackerSettings->setDopplerPeriod(settings.m_dopplerPeriod);
+ }
+ if (featureSettingsKeys.contains("defaultFrequency") || force) {
+ swgSatelliteTrackerSettings->setDefaultFrequency(settings.m_defaultFrequency);
+ }
+ if (featureSettingsKeys.contains("drawOnMap") || force) {
+ swgSatelliteTrackerSettings->setDrawOnMap(settings.m_drawOnMap);
+ }
+ if (featureSettingsKeys.contains("aosSpeech") || force) {
+ swgSatelliteTrackerSettings->setAosSpeech(new QString(settings.m_aosSpeech));
+ }
+ if (featureSettingsKeys.contains("losSpeech") || force) {
+ swgSatelliteTrackerSettings->setLosSpeech(new QString(settings.m_losSpeech));
+ }
+ if (featureSettingsKeys.contains("aosCommand") || force) {
+ swgSatelliteTrackerSettings->setAosCommand(new QString(settings.m_aosCommand));
+ }
+ if (featureSettingsKeys.contains("losCommand") || force) {
+ swgSatelliteTrackerSettings->setLosCommand(new QString(settings.m_losCommand));
+ }
+ if (featureSettingsKeys.contains("predictionPeriod") || force) {
+ swgSatelliteTrackerSettings->setPredictionPeriod(settings.m_predictionPeriod);
+ }
+ if (featureSettingsKeys.contains("passStartTime") || force) {
+ swgSatelliteTrackerSettings->setPassStartTime(new QString(settings.m_passStartTime.toString()));
+ }
+ if (featureSettingsKeys.contains("passFinishTime") || force) {
+ swgSatelliteTrackerSettings->setPassFinishTime(new QString(settings.m_passFinishTime.toString()));
+ }
+ if (featureSettingsKeys.contains("title") || force) {
+ swgSatelliteTrackerSettings->setTitle(new QString(settings.m_title));
+ }
+ if (featureSettingsKeys.contains("rgbColor") || force) {
+ swgSatelliteTrackerSettings->setRgbColor(settings.m_rgbColor);
+ }
+
+ QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings")
+ .arg(settings.m_reverseAPIAddress)
+ .arg(settings.m_reverseAPIPort)
+ .arg(settings.m_reverseAPIFeatureSetIndex)
+ .arg(settings.m_reverseAPIFeatureIndex);
+ m_networkRequest.setUrl(QUrl(channelSettingsURL));
+ m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ QBuffer *buffer = new QBuffer();
+ buffer->open((QBuffer::ReadWrite));
+ buffer->write(swgFeatureSettings->asJson().toUtf8());
+ buffer->seek(0);
+
+ // Always use PATCH to avoid passing reverse API settings
+ QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
+ buffer->setParent(reply);
+
+ delete swgFeatureSettings;
+}
+
+void SatelliteTracker::networkManagerFinished(QNetworkReply *reply)
+{
+ QNetworkReply::NetworkError replyError = reply->error();
+
+ if (replyError)
+ {
+ qWarning() << "SatelliteTracker::networkManagerFinished:"
+ << " error(" << (int) replyError
+ << "): " << replyError
+ << ": " << reply->errorString();
+ }
+ else
+ {
+ QString answer = reply->readAll();
+ answer.chop(1); // remove last \n
+ qDebug("SatelliteTracker::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
+ }
+
+ reply->deleteLater();
+}
+
+QString SatelliteTracker::satNogsSatellitesFilename()
+{
+ return HttpDownloadManager::downloadDir() + "/satnogs_satellites.json";
+}
+
+QString SatelliteTracker::satNogsTransmittersFilename()
+{
+ return HttpDownloadManager::downloadDir() + "/satnogs_transmitters.json";
+}
+
+QString SatelliteTracker::satNogsTLEFilename()
+{
+ return HttpDownloadManager::downloadDir() + "/satnogs_tle.json";
+}
+
+QString SatelliteTracker::tleURLToFilename(const QString& string)
+{
+ if (string == "https://db.satnogs.org/api/tle/")
+ return satNogsTLEFilename();
+ QUrl url(string);
+ return HttpDownloadManager::downloadDir() + "/tle_" + url.fileName();
+}
+
+void SatelliteTracker::downloadFinished(const QString& filename, bool success)
+{
+ if (success)
+ {
+ if (filename == satNogsSatellitesFilename())
+ {
+ m_dlm.download(QUrl("https://db.satnogs.org/api/transmitters/"), satNogsTransmittersFilename());
+ }
+ else if (filename == satNogsTransmittersFilename())
+ {
+ m_tleIndex = 0;
+ if (m_settings.m_tles.size() > 0)
+ m_dlm.download(QUrl(m_settings.m_tles[0]), tleURLToFilename(m_settings.m_tles[0]));
+ else
+ qWarning() << "Satellite Tracker: No TLEs";
+ }
+ else if ((m_tleIndex < m_settings.m_tles.size()) && (filename == tleURLToFilename(m_settings.m_tles[m_tleIndex])))
+ {
+ m_tleIndex++;
+ if (m_tleIndex < m_settings.m_tles.size())
+ m_dlm.download(QUrl(m_settings.m_tles[m_tleIndex]), tleURLToFilename(m_settings.m_tles[m_tleIndex]));
+ else
+ {
+ readSatData();
+ m_updatingSatData = false;
+ }
+ }
+ else
+ qDebug() << "SatelliteTracker::downloadFinished: Unexpected filename: " << filename;
+ }
+ else
+ m_updatingSatData = false;
+}
+
+bool SatelliteTracker::readSatData()
+{
+ QFile satsFile(satNogsSatellitesFilename());
+ if (satsFile.open(QIODevice::ReadOnly))
+ {
+ if (parseSatellites(satsFile.readAll()))
+ {
+ QFile transmittersFile(satNogsTransmittersFilename());
+ if (transmittersFile.open(QIODevice::ReadOnly))
+ {
+ if (parseTransmitters(transmittersFile.readAll()))
+ {
+ for (int i = 0; i < m_settings.m_tles.size(); i++)
+ {
+ QFile tlesFile(tleURLToFilename(m_settings.m_tles[i]));
+ if (tlesFile.open(QIODevice::ReadOnly))
+ {
+ bool ok;
+ if (tlesFile.fileName() == satNogsTLEFilename())
+ {
+ ok = parseSatNogsTLEs(tlesFile.readAll());
+ }
+ else
+ ok = parseTxtTLEs(tlesFile.readAll());
+ if (!ok)
+ qDebug() << "SatelliteTracker::readSatData - failed to parse: " << tlesFile.fileName();
+ }
+ else
+ qDebug() << "SatelliteTracker::readSatData - failed to open: " << tlesFile.fileName();
+ }
+
+ qDebug() << "SatelliteTracker::readSatData - read " << m_satellites.size() << " satellites";
+
+ // Send to GUI
+ if (m_guiMessageQueue)
+ m_guiMessageQueue->push(MsgSatData::create(m_satellites));
+ // Send to worker
+ m_worker->getInputMessageQueue()->push(MsgSatData::create(m_satellites));
+
+ return true;
+ }
+ }
+ }
+ }
+ qDebug() << "SatelliteTracker::readSatData - Failed to read satellites";
+ return false;
+}
+
+bool SatelliteTracker::parseSatellites(const QByteArray& json)
+{
+ QJsonDocument jsonResponse = QJsonDocument::fromJson(json);
+
+ if (jsonResponse.isArray())
+ {
+ m_satellites = SatNogsSatellite::createHash(jsonResponse.array());
+ m_satellitesId.clear();
+
+ // Create second table, hashed on ID
+ QHashIterator i(m_satellites);
+ while (i.hasNext())
+ {
+ i.next();
+ SatNogsSatellite *sat = i.value();
+ m_satellitesId.insert(sat->m_noradCatId, sat);
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool SatelliteTracker::parseTransmitters(const QByteArray& json)
+{
+ QJsonDocument jsonResponse = QJsonDocument::fromJson(json);
+
+ if (jsonResponse.isArray())
+ {
+ QList transmitters = SatNogsTransmitter::createList(jsonResponse.array());
+
+ QHashIterator i(m_satellites);
+ while (i.hasNext())
+ {
+ i.next();
+ SatNogsSatellite *sat = i.value();
+ sat->addTransmitters(transmitters);
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool SatelliteTracker::parseSatNogsTLEs(const QByteArray& json)
+{
+ QJsonDocument jsonResponse = QJsonDocument::fromJson(json);
+
+ if (jsonResponse.isArray())
+ {
+ QList tles = SatNogsTLE::createList(jsonResponse.array());
+
+ QHashIterator i(m_satellites);
+ while (i.hasNext())
+ {
+ i.next();
+ SatNogsSatellite *sat = i.value();
+ sat->addTLE(tles);
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool SatelliteTracker::parseTxtTLEs(const QByteArray& txt)
+{
+ QList tles = SatNogsTLE::createList(txt);
+
+ QHashIterator i(m_satellites);
+ while (i.hasNext())
+ {
+ i.next();
+ SatNogsSatellite *sat = i.value();
+ sat->addTLE(tles);
+ }
+
+ // Create satellites, that we have TLEs for, but no existing entry
+ for (int i = 0; i < tles.size(); i++)
+ {
+ if (!m_satellitesId.contains(tles[i]->m_noradCatId))
+ {
+ SatNogsSatellite *sat = new SatNogsSatellite(tles[i]);
+ m_satellites.insert(sat->m_name, sat);
+ m_satellitesId.insert(sat->m_noradCatId, sat);
+ }
+ }
+
+ return true;
+}
+
+void SatelliteTracker::updateSatData()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+
+ if (m_updatingSatData == false)
+ {
+ m_updatingSatData = true;
+ qDebug() << "SatelliteTracker::updateSatData: requesting satellites";
+ m_dlm.download(QUrl("https://db.satnogs.org/api/satellites/"), satNogsSatellitesFilename());
+ }
+ else
+ qDebug() << "SatelliteTracker::updateSatData: update in progress";
+}
diff --git a/plugins/feature/satellitetracker/satellitetracker.h b/plugins/feature/satellitetracker/satellitetracker.h
new file mode 100644
index 000000000..53e704959
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetracker.h
@@ -0,0 +1,200 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITETRACKER_H_
+#define INCLUDE_FEATURE_SATELLITETRACKER_H_
+
+#include
+#include
+
+#include "feature/feature.h"
+#include "util/message.h"
+#include "util/httpdownloadmanager.h"
+
+#include "satellitetrackersettings.h"
+#include "satnogs.h"
+
+class WebAPIAdapterInterface;
+class SatelliteTrackerWorker;
+class QNetworkAccessManager;
+class QNetworkReply;
+
+namespace SWGSDRangel {
+ class SWGDeviceState;
+}
+
+class SatelliteTracker : public Feature
+{
+ Q_OBJECT
+public:
+ class MsgConfigureSatelliteTracker : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const SatelliteTrackerSettings& getSettings() const { return m_settings; }
+ bool getForce() const { return m_force; }
+
+ static MsgConfigureSatelliteTracker* create(const SatelliteTrackerSettings& settings, bool force) {
+ return new MsgConfigureSatelliteTracker(settings, force);
+ }
+
+ private:
+ SatelliteTrackerSettings m_settings;
+ bool m_force;
+
+ MsgConfigureSatelliteTracker(const SatelliteTrackerSettings& settings, bool force) :
+ Message(),
+ m_settings(settings),
+ m_force(force)
+ { }
+ };
+
+ class MsgStartStop : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ bool getStartStop() const { return m_startStop; }
+
+ static MsgStartStop* create(bool startStop) {
+ return new MsgStartStop(startStop);
+ }
+
+ protected:
+ bool m_startStop;
+
+ MsgStartStop(bool startStop) :
+ Message(),
+ m_startStop(startStop)
+ { }
+ };
+
+ class MsgUpdateSatData : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+
+ static MsgUpdateSatData* create() {
+ return new MsgUpdateSatData();
+ }
+
+ private:
+
+ MsgUpdateSatData() :
+ Message()
+ { }
+ };
+
+ class MsgSatData : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ QHash getSatellites() { return m_satellites; }
+
+ static MsgSatData* create(QHash satellites) {
+ return new MsgSatData(satellites);
+ }
+
+ private:
+ QHash m_satellites;
+
+ MsgSatData(QHash satellites) :
+ Message(),
+ m_satellites(satellites)
+ { }
+ };
+
+ SatelliteTracker(WebAPIAdapterInterface *webAPIAdapterInterface);
+ virtual ~SatelliteTracker();
+ virtual void destroy() { delete this; }
+ virtual bool handleMessage(const Message& cmd);
+
+ virtual void getIdentifier(QString& id) const { id = objectName(); }
+ virtual void getTitle(QString& title) const { title = m_settings.m_title; }
+
+ virtual QByteArray serialize() const;
+ virtual bool deserialize(const QByteArray& data);
+
+ virtual int webapiRun(bool run,
+ SWGSDRangel::SWGDeviceState& response,
+ QString& errorMessage);
+
+ virtual int webapiSettingsGet(
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage);
+
+ virtual int webapiSettingsPutPatch(
+ bool force,
+ const QStringList& featureSettingsKeys,
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage);
+
+ static void webapiFormatFeatureSettings(
+ SWGSDRangel::SWGFeatureSettings& response,
+ const SatelliteTrackerSettings& settings);
+
+ static void webapiUpdateFeatureSettings(
+ SatelliteTrackerSettings& settings,
+ const QStringList& featureSettingsKeys,
+ SWGSDRangel::SWGFeatureSettings& response);
+
+ static const char* const m_featureIdURI;
+ static const char* const m_featureId;
+
+ bool isUpdatingSatData() { return m_updatingSatData; }
+
+private:
+ QThread m_thread;
+ SatelliteTrackerWorker *m_worker;
+ SatelliteTrackerSettings m_settings;
+
+ QNetworkAccessManager *m_networkManager;
+ QNetworkRequest m_networkRequest;
+ HttpDownloadManager m_dlm;
+ bool m_updatingSatData;
+ int m_tleIndex;
+ QMutex m_mutex;
+
+ QHash m_satellites; // Satellites, hashed on name
+ QHash m_satellitesId; // Same data as m_satellites, but hashed on id, rather than name
+ bool m_firstUpdateSatData;
+
+ void start();
+ void stop();
+ void applySettings(const SatelliteTrackerSettings& settings, bool force = false);
+ void webapiReverseSendSettings(QList& featureSettingsKeys, const SatelliteTrackerSettings& settings, bool force);
+
+ QString satNogsSatellitesFilename();
+ QString satNogsTransmittersFilename();
+ QString satNogsTLEFilename();
+ QString tleURLToFilename(const QString& string);
+ bool parseSatellites(const QByteArray& json);
+ bool parseTransmitters(const QByteArray& json);
+ bool parseSatNogsTLEs(const QByteArray& json);
+ bool parseTxtTLEs(const QByteArray& txt);
+ bool readSatData();
+ void updateSatData();
+ void updateSatellitesReply(QNetworkReply *reply);
+ void updateTransmittersReply(QNetworkReply *reply);
+ void updateTLEsReply(QNetworkReply *reply);
+
+private slots:
+ void networkManagerFinished(QNetworkReply *reply);
+ void downloadFinished(const QString& filename, bool success);
+};
+
+#endif // INCLUDE_FEATURE_SATELLITETRACKER_H_
diff --git a/plugins/feature/satellitetracker/satellitetracker.qrc b/plugins/feature/satellitetracker/satellitetracker.qrc
new file mode 100644
index 000000000..fc9e1498e
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetracker.qrc
@@ -0,0 +1,6 @@
+
+
+ satellitetracker/iss-32.png
+ satellitetracker/satellite-32.png
+
+
diff --git a/plugins/feature/satellitetracker/satellitetracker/iss-32.png b/plugins/feature/satellitetracker/satellitetracker/iss-32.png
new file mode 100644
index 000000000..ed1479e85
Binary files /dev/null and b/plugins/feature/satellitetracker/satellitetracker/iss-32.png differ
diff --git a/plugins/feature/satellitetracker/satellitetracker/satellite-32.png b/plugins/feature/satellitetracker/satellitetracker/satellite-32.png
new file mode 100644
index 000000000..6e6bd78c2
Binary files /dev/null and b/plugins/feature/satellitetracker/satellitetracker/satellite-32.png differ
diff --git a/plugins/feature/satellitetracker/satellitetrackergui.cpp b/plugins/feature/satellitetracker/satellitetrackergui.cpp
new file mode 100644
index 000000000..d578fabc8
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackergui.cpp
@@ -0,0 +1,1161 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "feature/featureuiset.h"
+#include "feature/featurewebapiutils.h"
+#include "gui/basicfeaturesettingsdialog.h"
+#include "mainwindow.h"
+#include "device/deviceuiset.h"
+#include "util/units.h"
+#include "util/astronomy.h"
+
+#include "ui_satellitetrackergui.h"
+#include "satellitetracker.h"
+#include "satellitetrackergui.h"
+#include "satellitetrackerreport.h"
+#include "satellitetrackersettingsdialog.h"
+#include "satelliteselectiondialog.h"
+#include "satelliteradiocontroldialog.h"
+#include "satellitetrackersgp4.h"
+
+SatelliteTrackerGUI* SatelliteTrackerGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
+{
+ SatelliteTrackerGUI* gui = new SatelliteTrackerGUI(pluginAPI, featureUISet, feature);
+ return gui;
+}
+
+void SatelliteTrackerGUI::destroy()
+{
+ delete this;
+}
+
+void SatelliteTrackerGUI::resetToDefaults()
+{
+ m_settings.resetToDefaults();
+ displaySettings();
+ applySettings(true);
+}
+
+QByteArray SatelliteTrackerGUI::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool SatelliteTrackerGUI::deserialize(const QByteArray& data)
+{
+ if (m_settings.deserialize(data))
+ {
+ updateSelectedSats();
+ displaySettings();
+ qDebug() << " deserialize " << m_settings.m_satellites;
+ applySettings(true);
+ return true;
+ }
+ else
+ {
+ resetToDefaults();
+ return false;
+ }
+}
+
+QString SatelliteTrackerGUI::convertDegreesToText(double degrees)
+{
+ if (m_settings.m_azElUnits == SatelliteTrackerSettings::DMS)
+ return Units::decimalDegreesToDegreeMinutesAndSeconds(degrees);
+ else if (m_settings.m_azElUnits == SatelliteTrackerSettings::DM)
+ return Units::decimalDegreesToDegreesAndMinutes(degrees);
+ else if (m_settings.m_azElUnits == SatelliteTrackerSettings::D)
+ return Units::decimalDegreesToDegrees(degrees);
+ else
+ return QString("%1").arg(degrees, 0, 'f', 2);
+}
+
+bool SatelliteTrackerGUI::handleMessage(const Message& message)
+{
+ if (SatelliteTracker::MsgConfigureSatelliteTracker::match(message))
+ {
+ qDebug("SatelliteTrackerGUI::handleMessage: SatelliteTracker::MsgConfigureSatelliteTracker");
+ const SatelliteTracker::MsgConfigureSatelliteTracker& cfg = (SatelliteTracker::MsgConfigureSatelliteTracker&) message;
+ m_settings = cfg.getSettings();
+ blockApplySettings(true);
+ displaySettings();
+ blockApplySettings(false);
+
+ return true;
+ }
+ else if (SatelliteTrackerReport::MsgReportSat::match(message))
+ {
+ SatelliteTrackerReport::MsgReportSat& satReport = (SatelliteTrackerReport::MsgReportSat&) message;
+ SatelliteState *satState = satReport.getSatelliteState();
+ if (satState->m_name == m_settings.m_target)
+ {
+ delete m_targetSatState;
+ m_targetSatState = satState;
+
+ ui->azimuth->setText(convertDegreesToText(satState->m_azimuth));
+ ui->elevation->setText(convertDegreesToText(satState->m_elevation));
+ if (satState->m_passes.size() > 0)
+ {
+ SatellitePass *pass = satState->m_passes[0];
+ bool geostationary = !pass->m_aos.isValid() && !pass->m_los.isValid();
+ if ((m_nextTargetAOS != pass->m_aos) || (m_nextTargetLOS != pass->m_los) || (geostationary != m_geostationarySatVisible))
+ {
+ m_nextTargetAOS = pass->m_aos;
+ m_nextTargetLOS = pass->m_los;
+ m_geostationarySatVisible = geostationary;
+ plotChart();
+ updateTimeToAOS();
+ }
+ }
+ }
+ updateTable(satState);
+ if (satState->m_name != m_settings.m_target)
+ delete satState;
+ return true;
+ }
+ else if (SatelliteTrackerReport::MsgReportAOS::match(message))
+ {
+ SatelliteTrackerReport::MsgReportAOS& aosReport = (SatelliteTrackerReport::MsgReportAOS&) message;
+ aos(aosReport.getName(), aosReport.getDuration(), aosReport.getMaxElevation());
+ return true;
+ }
+ else if (SatelliteTrackerReport::MsgReportTarget::match(message))
+ {
+ SatelliteTrackerReport::MsgReportTarget& targetReport = (SatelliteTrackerReport::MsgReportTarget&) message;
+ setTarget(targetReport.getName());
+ return true;
+ }
+ else if (SatelliteTrackerReport::MsgReportLOS::match(message))
+ {
+ SatelliteTrackerReport::MsgReportLOS& losReport = (SatelliteTrackerReport::MsgReportLOS&) message;
+ los(losReport.getName());
+ return true;
+ }
+ else if (SatelliteTracker::MsgSatData::match(message))
+ {
+ SatelliteTracker::MsgSatData& satData = (SatelliteTracker::MsgSatData&) message;
+ m_satellites = satData.getSatellites();
+ // Remove satellites that no longer exist
+ QMutableListIterator itr(m_settings.m_satellites);
+ while (itr.hasNext())
+ {
+ QString satellite = itr.next();
+ if (!m_satellites.contains(satellite))
+ itr.remove();
+ }
+ if (!m_satellites.contains(m_settings.m_target))
+ setTarget("");
+ // Update GUI
+ updateSelectedSats();
+ return true;
+ }
+
+ return false;
+}
+
+// Call when m_settings.m_satellites changes
+void SatelliteTrackerGUI::updateSelectedSats()
+{
+ // Remove unselects sats from target combo and table
+ for (int i = 0; i < ui->target->count(); )
+ {
+ QString name = ui->target->itemText(i);
+ int idx = m_settings.m_satellites.indexOf(name);
+ if (idx == -1)
+ {
+ ui->target->removeItem(i);
+ QList matches = ui->satTable->findItems(name, Qt::MatchExactly);
+ for (int j = 0; j < matches.length(); j++)
+ ui->satTable->removeRow(ui->satTable->row(matches[j]));
+ }
+ else
+ i++;
+ }
+ // Add new satellites to target combo
+ for (int i = 0; i < m_settings.m_satellites.size(); i++)
+ {
+ if (ui->target->findText(m_settings.m_satellites[i], Qt::MatchExactly) == -1)
+ ui->target->addItem(m_settings.m_satellites[i]);
+ }
+ // Select current target, if it still exists
+ int idx = ui->target->findText(m_settings.m_target);
+ if (idx != -1)
+ ui->target->setCurrentIndex(idx);
+ else
+ setTarget("");
+}
+
+void SatelliteTrackerGUI::handleInputMessages()
+{
+ Message* message;
+
+ while ((message = getInputMessageQueue()->pop()))
+ {
+ if (handleMessage(*message)) {
+ delete message;
+ }
+ }
+}
+
+void SatelliteTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
+{
+ (void) widget;
+ (void) rollDown;
+}
+
+SatelliteTrackerGUI::SatelliteTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
+ FeatureGUI(parent),
+ ui(new Ui::SatelliteTrackerGUI),
+ m_pluginAPI(pluginAPI),
+ m_featureUISet(featureUISet),
+ m_doApplySettings(true),
+ m_lastFeatureState(0),
+ m_lastUpdatingSatData(false),
+ m_targetSatState(nullptr),
+ m_plotPass(0),
+ m_lineChart(nullptr),
+ m_polarChart(nullptr),
+ m_geostationarySatVisible(false)
+{
+ ui->setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ setChannelWidget(false);
+ connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
+ m_satelliteTracker = reinterpret_cast(feature);
+ m_satelliteTracker->setMessageQueueToGUI(&m_inputMessageQueue);
+
+ m_featureUISet->addRollupWidget(this);
+
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
+ connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
+
+ connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
+ m_statusTimer.start(1000);
+
+ // Intialise charts
+ m_emptyChart.layout()->setContentsMargins(0, 0, 0, 0);
+ m_emptyChart.setMargins(QMargins(1, 1, 1, 1));
+ ui->passChart->setChart(&m_emptyChart);
+ ui->passChart->setRenderHint(QPainter::Antialiasing);
+
+ ui->dateTime->setDateTime(QDateTime::currentDateTime());
+
+ // Use My Position from preferences, if none set
+ if ((m_settings.m_latitude == 0.0) && (m_settings.m_longitude == 0.0))
+ on_useMyPosition_clicked();
+
+ resizeTable();
+ // Allow user to reorder columns
+ ui->satTable->horizontalHeader()->setSectionsMovable(true);
+ // Allow user to sort table by clicking on headers
+ ui->satTable->setSortingEnabled(true);
+ // Add context menu to allow hiding/showing of columns
+ menu = new QMenu(ui->satTable);
+ for (int i = 0; i < ui->satTable->horizontalHeader()->count(); i++)
+ {
+ QString text = ui->satTable->horizontalHeaderItem(i)->text();
+ menu->addAction(createCheckableItem(text, i, true));
+ }
+ ui->satTable->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->satTable->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(columnSelectMenu(QPoint)));
+ // Get signals when columns change
+ connect(ui->satTable->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), SLOT(satTable_sectionMoved(int, int, int)));
+ connect(ui->satTable->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(satTable_sectionResized(int, int, int)));
+
+ m_speech = new QTextToSpeech(this);
+
+ displaySettings();
+ applySettings(true);
+
+ // Get initial list of satellites
+ on_updateSatData_clicked();
+}
+
+SatelliteTrackerGUI::~SatelliteTrackerGUI()
+{
+ delete ui;
+}
+
+void SatelliteTrackerGUI::blockApplySettings(bool block)
+{
+ m_doApplySettings = !block;
+}
+
+void SatelliteTrackerGUI::displaySettings()
+{
+ setTitleColor(m_settings.m_rgbColor);
+ setWindowTitle(m_settings.m_title);
+ blockApplySettings(true);
+ ui->latitude->setValue(m_settings.m_latitude);
+ ui->longitude->setValue(m_settings.m_longitude);
+ ui->target->setCurrentIndex(ui->target->findText(m_settings.m_target));
+ if (m_settings.m_dateTime == "")
+ {
+ ui->dateTimeSelect->setCurrentIndex(0);
+ ui->dateTime->setVisible(false);
+ }
+ else
+ {
+ ui->dateTime->setDateTime(QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs));
+ ui->dateTime->setVisible(true);
+ ui->dateTimeSelect->setCurrentIndex(1);
+ }
+ ui->autoTarget->setChecked(m_settings.m_autoTarget);
+ plotChart();
+ blockApplySettings(false);
+}
+
+void SatelliteTrackerGUI::leaveEvent(QEvent*)
+{
+}
+
+void SatelliteTrackerGUI::enterEvent(QEvent*)
+{
+}
+
+void SatelliteTrackerGUI::onMenuDialogCalled(const QPoint &p)
+{
+ if (m_contextMenuType == ContextMenuChannelSettings)
+ {
+ BasicFeatureSettingsDialog dialog(this);
+ dialog.setTitle(m_settings.m_title);
+ dialog.setColor(m_settings.m_rgbColor);
+ dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
+ dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
+ dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
+ dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex);
+ dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex);
+
+ dialog.move(p);
+ dialog.exec();
+
+ m_settings.m_rgbColor = dialog.getColor().rgb();
+ m_settings.m_title = dialog.getTitle();
+ m_settings.m_useReverseAPI = dialog.useReverseAPI();
+ m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
+ m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
+ m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex();
+ m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex();
+
+ setWindowTitle(m_settings.m_title);
+ setTitleColor(m_settings.m_rgbColor);
+
+ applySettings();
+ }
+
+ resetContextMenuType();
+}
+
+void SatelliteTrackerGUI::aos(const QString& name, int duration, int maxElevation)
+{
+ // Give speech notification of pass
+ QString speech = m_settings.m_aosSpeech.trimmed();
+ if (!speech.isEmpty())
+ {
+ speech = speech.replace("${name}", name);
+ speech = speech.replace("${duration}", QString::number(duration));
+ speech = speech.replace("${elevation}", QString::number(maxElevation));
+ m_speech->say(speech);
+ }
+}
+
+void SatelliteTrackerGUI::los(const QString& name)
+{
+ // Give speech notification of end of pass
+ QString speech = m_settings.m_losSpeech.trimmed();
+ if (!speech.isEmpty())
+ {
+ speech = speech.replace("${name}", name);
+ m_speech->say(speech);
+ }
+}
+
+void SatelliteTrackerGUI::on_startStop_toggled(bool checked)
+{
+ if (m_doApplySettings)
+ {
+ SatelliteTracker::MsgStartStop *message = SatelliteTracker::MsgStartStop::create(checked);
+ m_satelliteTracker->getInputMessageQueue()->push(message);
+ }
+}
+
+void SatelliteTrackerGUI::on_latitude_valueChanged(double value)
+{
+ m_settings.m_latitude = value;
+ applySettings();
+ plotChart();
+}
+
+void SatelliteTrackerGUI::on_longitude_valueChanged(double value)
+{
+ m_settings.m_longitude = value;
+ applySettings();
+ plotChart();
+}
+
+void SatelliteTrackerGUI::setTarget(const QString& target)
+{
+ if (target != m_settings.m_target)
+ {
+ m_settings.m_target = target;
+ ui->azimuth->setText("");
+ ui->elevation->setText("");
+ ui->aos->setText("");
+ ui->target->setCurrentIndex(ui->target->findText(m_settings.m_target));
+ m_nextTargetAOS = QDateTime();
+ m_nextTargetLOS = QDateTime();
+ m_geostationarySatVisible = false;
+ applySettings();
+ delete m_targetSatState;
+ m_targetSatState = nullptr;
+ m_plotPass = 0;
+ ui->passLabel->setText(QString("%1").arg(m_plotPass));
+ plotChart();
+ }
+}
+
+void SatelliteTrackerGUI::on_target_currentTextChanged(const QString &text)
+{
+ setTarget(text);
+}
+
+void SatelliteTrackerGUI::on_useMyPosition_clicked(bool checked)
+{
+ (void) checked;
+ double stationLatitude = MainCore::instance()->getSettings().getLatitude();
+ double stationLongitude = MainCore::instance()->getSettings().getLongitude();
+ double stationAltitude = MainCore::instance()->getSettings().getAltitude();
+
+ ui->latitude->setValue(stationLatitude);
+ ui->longitude->setValue(stationLongitude);
+ m_settings.m_heightAboveSeaLevel = stationAltitude;
+ applySettings();
+ plotChart();
+}
+
+// Show settings dialog
+void SatelliteTrackerGUI::on_displaySettings_clicked()
+{
+ SatelliteTrackerSettingsDialog dialog(&m_settings);
+ if (dialog.exec() == QDialog::Accepted)
+ {
+ applySettings();
+ plotChart();
+ }
+}
+
+void SatelliteTrackerGUI::on_dateTimeSelect_currentTextChanged(const QString &text)
+{
+ if (text == "Now")
+ {
+ m_settings.m_dateTime = "";
+ ui->dateTime->setVisible(false);
+ }
+ else
+ {
+ m_settings.m_dateTime = ui->dateTime->dateTime().toString(Qt::ISODateWithMs);
+ ui->dateTime->setVisible(true);
+ }
+ applySettings();
+ plotChart();
+}
+
+void SatelliteTrackerGUI::on_dateTime_dateTimeChanged(const QDateTime &datetime)
+{
+ (void) datetime;
+ if (ui->dateTimeSelect->currentIndex() == 1)
+ {
+ m_settings.m_dateTime = ui->dateTime->dateTime().toString(Qt::ISODateWithMs);
+ applySettings();
+ plotChart();
+ }
+}
+
+// Find target on the Map
+void SatelliteTrackerGUI::on_viewOnMap_clicked()
+{
+ if (!m_settings.m_target.isEmpty())
+ FeatureWebAPIUtils::mapFind(m_settings.m_target);
+}
+
+void SatelliteTrackerGUI::on_updateSatData_clicked()
+{
+ m_satelliteTracker->getInputMessageQueue()->push(SatelliteTracker::MsgUpdateSatData::create());
+}
+
+void SatelliteTrackerGUI::on_selectSats_clicked()
+{
+ SatelliteSelectionDialog dialog(&m_settings, m_satellites);
+ if (dialog.exec() == QDialog::Accepted)
+ {
+ updateSelectedSats();
+ applySettings();
+ }
+}
+
+void SatelliteTrackerGUI::on_radioControl_clicked()
+{
+ SatelliteRadioControlDialog dialog(&m_settings, m_satellites);
+ if (dialog.exec() == QDialog::Accepted)
+ applySettings();
+}
+
+void SatelliteTrackerGUI::on_autoTarget_clicked(bool checked)
+{
+ m_settings.m_autoTarget = checked;
+ applySettings();
+}
+
+void SatelliteTrackerGUI::updateStatus()
+{
+ int state = m_satelliteTracker->getState();
+
+ if (m_lastFeatureState != state)
+ {
+ // We set checked state of start/stop button, in case it was changed via API
+ bool oldState;
+ switch (state)
+ {
+ case Feature::StNotStarted:
+ ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
+ break;
+ case Feature::StIdle:
+ oldState = ui->startStop->blockSignals(true);
+ ui->startStop->setChecked(false);
+ ui->startStop->blockSignals(oldState);
+ ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
+ break;
+ case Feature::StRunning:
+ oldState = ui->startStop->blockSignals(true);
+ ui->startStop->setChecked(true);
+ ui->startStop->blockSignals(oldState);
+ ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
+ break;
+ case Feature::StError:
+ ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
+ QMessageBox::information(this, tr("Message"), m_satelliteTracker->getErrorMessage());
+ break;
+ default:
+ break;
+ }
+
+ m_lastFeatureState = state;
+ }
+
+ // Indicate if satellite data is being updated
+ bool updatingSatData = m_satelliteTracker->isUpdatingSatData();
+ if (updatingSatData != m_lastUpdatingSatData)
+ {
+ if (updatingSatData)
+ ui->updateSatData->setStyleSheet("QToolButton { background-color : green; }");
+ else
+ ui->updateSatData->setStyleSheet("QToolButton { background: none; }");
+ m_lastUpdatingSatData = updatingSatData;
+ }
+
+ updateTimeToAOS();
+}
+
+// Update time to AOS
+void SatelliteTrackerGUI::updateTimeToAOS()
+{
+ if (m_geostationarySatVisible)
+ ui->aos->setText("Now");
+ else if (m_nextTargetAOS.isValid())
+ {
+ QDateTime currentTime = QDateTime::currentDateTime();
+ int secondsToAOS = m_nextTargetAOS.toSecsSinceEpoch() - currentTime.toSecsSinceEpoch();
+ if (secondsToAOS > 0)
+ {
+ int seconds = secondsToAOS % 60;
+ int minutes = (secondsToAOS / 60) % 60;
+ int hours = (secondsToAOS / (60 * 60)) % 24;
+ int days = secondsToAOS / (60 * 60 * 24);
+ if (days == 1)
+ ui->aos->setText(QString("1 day"));
+ else if (days > 0)
+ ui->aos->setText(QString("%1 days").arg(days));
+ else
+ {
+ ui->aos->setText(QString("%1:%2:%3")
+ .arg(hours, 2, 10, QLatin1Char('0'))
+ .arg(minutes, 2, 10, QLatin1Char('0'))
+ .arg(seconds, 2, 10, QLatin1Char('0')));
+ }
+ }
+ else if (m_nextTargetLOS < currentTime)
+ ui->aos->setText("");
+ else
+ ui->aos->setText("Now");
+ }
+ else
+ ui->aos->setText("");
+}
+
+void SatelliteTrackerGUI::applySettings(bool force)
+{
+ if (m_doApplySettings)
+ {
+ SatelliteTracker::MsgConfigureSatelliteTracker* message = SatelliteTracker::MsgConfigureSatelliteTracker::create(m_settings, force);
+ m_satelliteTracker->getInputMessageQueue()->push(message);
+ }
+}
+
+void SatelliteTrackerGUI::on_nextPass_clicked()
+{
+ if (m_targetSatState != nullptr)
+ {
+ if (m_plotPass < m_targetSatState->m_passes.size() - 1)
+ {
+ m_plotPass++;
+ ui->passLabel->setText(QString("%1").arg(m_plotPass));
+ plotChart();
+ }
+ }
+}
+
+void SatelliteTrackerGUI::on_prevPass_clicked()
+{
+ if (m_plotPass > 0)
+ {
+ m_plotPass--;
+ ui->passLabel->setText(QString("%1").arg(m_plotPass));
+ plotChart();
+ }
+}
+
+void SatelliteTrackerGUI::on_chartSelect_currentIndexChanged(int index)
+{
+ (void) index;
+ plotChart();
+}
+
+void SatelliteTrackerGUI::plotChart()
+{
+ if (ui->chartSelect->currentIndex() == 0)
+ plotPolarChart();
+ else
+ plotAzElChart();
+}
+
+// Linear interpolation
+static double interpolate(double x0, double y0, double x1, double y1, double x)
+{
+ return (y0*(x1-x) + y1*(x-x0)) / (x1-x0);
+}
+
+// Plot pass in polar coords
+void SatelliteTrackerGUI::plotPolarChart()
+{
+ if ((m_targetSatState == nullptr) || !m_satellites.contains(m_settings.m_target) || (m_targetSatState->m_passes.size() == 0))
+ {
+ ui->passChart->setChart(&m_emptyChart);
+ return;
+ }
+
+ QChart *oldChart = m_polarChart;
+
+ if (m_plotPass >= m_targetSatState->m_passes.size() - 1)
+ {
+ m_plotPass = m_targetSatState->m_passes.size() - 1;
+ ui->passLabel->setText(QString("%1").arg(m_plotPass));
+ }
+ SatellitePass *pass = m_targetSatState->m_passes[m_plotPass];
+
+ // Always create a new chart, otherwise sometimes they aren't drawn properly
+ m_polarChart = new QPolarChart();
+ QValueAxis *angularAxis = new QValueAxis();
+ QCategoryAxis *radialAxis = new QCategoryAxis();
+
+ angularAxis->setTickCount(9);
+ angularAxis->setMinorTickCount(1);
+ angularAxis->setLabelFormat("%d");
+ angularAxis->setRange(0, 360);
+
+ radialAxis->setMin(0);
+ radialAxis->setMax(90);
+ radialAxis->append("90", 0);
+ radialAxis->append("60", 30);
+ radialAxis->append("30", 60);
+ radialAxis->append("0", 90);
+ radialAxis->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
+
+ m_polarChart->addAxis(angularAxis, QPolarChart::PolarOrientationAngular);
+ m_polarChart->addAxis(radialAxis, QPolarChart::PolarOrientationRadial);
+ m_polarChart->legend()->hide();
+ m_polarChart->layout()->setContentsMargins(0, 0, 0, 0);
+ m_polarChart->setMargins(QMargins(1, 1, 1, 1));
+
+ SatNogsSatellite *sat = m_satellites.value(m_settings.m_target);
+
+ if (pass->m_aos.isValid() && pass->m_los.isValid())
+ {
+ QString title;
+ if (m_settings.m_utc)
+ title = pass->m_aos.date().toString(m_settings.m_dateFormat);
+ else
+ title = pass->m_aos.toLocalTime().date().toString(m_settings.m_dateFormat);
+ m_polarChart->setTitle(QString("%1").arg(title));
+
+ QLineSeries *polarSeries = new QLineSeries();
+
+ getPassAzEl(nullptr, nullptr, polarSeries,
+ sat->m_tle->m_tle0, sat->m_tle->m_tle1, sat->m_tle->m_tle2,
+ m_settings.m_latitude, m_settings.m_longitude, m_settings.m_heightAboveSeaLevel/1000.0,
+ pass->m_aos, pass->m_los);
+
+ // Polar charts can't handle points that are more than 180 degrees apart, so
+ // we need to split passes that cross from 359 -> 0 degrees (or the reverse)
+ QList series;
+ series.append(new QLineSeries());
+ QLineSeries *s = series.first();
+ QPen pen(QColor(32, 159, 223), 2, Qt::SolidLine);
+ s->setPen(pen);
+
+ qreal prevAz = polarSeries->at(0).x();
+ qreal prevEl = polarSeries->at(0).y();
+ for (int i = 1; i < polarSeries->count(); i++)
+ {
+ qreal az = polarSeries->at(i).x();
+ qreal el = polarSeries->at(i).y();
+ if ((prevAz > 270.0) && (az <= 90.0))
+ {
+ double elMid = interpolate(prevAz, prevEl, az+360.0, el, 360.0);
+ s->append(360.0, elMid);
+ series.append(new QLineSeries());
+ s = series.last();
+ s->setPen(pen);
+ s->append(0.0, elMid);
+ s->append(az, el);
+ }
+ else if ((prevAz <= 90.0) && (az > 270.0))
+ {
+ double elMid = interpolate(prevAz, prevEl, az-360.0, el, 0.0);
+ s->append(0.0, elMid);
+ series.append(new QLineSeries());
+ s = series.last();
+ s->setPen(pen);
+ s->append(360.0, elMid);
+ s->append(az, el);
+ }
+ else
+ s->append(polarSeries->at(i));
+ prevAz = az;
+ prevEl = el;
+ }
+
+ for (int i = 0; i < series.length(); i++)
+ {
+ m_polarChart->addSeries(series[i]);
+ series[i]->attachAxis(angularAxis);
+ series[i]->attachAxis(radialAxis);
+ }
+
+ // Create series with single point, so we can plot time of AOS
+ QLineSeries *aosSeries = new QLineSeries();
+ aosSeries->append(polarSeries->at(0));
+ QTime time;
+ if (m_settings.m_utc)
+ time = pass->m_aos.time();
+ else
+ time = pass->m_aos.toLocalTime().time();
+ if (m_settings.m_utc)
+ aosSeries->setPointLabelsFormat(QString("AOS %1").arg(time.toString("hh:mm")));
+ else
+ aosSeries->setPointLabelsFormat(QString("AOS %1").arg(time.toString("hh:mm")));
+ aosSeries->setPointLabelsVisible(true);
+ aosSeries->setPointLabelsClipping(false);
+ m_polarChart->addSeries(aosSeries);
+ aosSeries->attachAxis(angularAxis);
+ aosSeries->attachAxis(radialAxis);
+ // Create series with single point, so we can plot time of LOS
+ QLineSeries *losSeries = new QLineSeries();
+ losSeries->append(polarSeries->at(polarSeries->count()-1));
+ if (m_settings.m_utc)
+ time = pass->m_los.time();
+ else
+ time = pass->m_los.toLocalTime().time();
+ losSeries->setPointLabelsFormat(QString("LOS %1").arg(time.toString("hh:mm")));
+ losSeries->setPointLabelsVisible(true);
+ losSeries->setPointLabelsClipping(false);
+ m_polarChart->addSeries(losSeries);
+ losSeries->attachAxis(angularAxis);
+ losSeries->attachAxis(radialAxis);
+
+ QDateTime currentTime;
+ if (m_settings.m_dateTime == "")
+ currentTime = QDateTime::currentDateTimeUtc();
+ else if (m_settings.m_utc)
+ currentTime = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
+ else
+ currentTime = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs).toUTC();
+ if ((currentTime >= pass->m_aos) && (currentTime <= pass->m_los))
+ {
+ // Create series with single point, so we can plot current time
+ QLineSeries *nowSeries = new QLineSeries();
+ // Find closest point to current time
+ int idx = std::round(polarSeries->count() * (currentTime.toMSecsSinceEpoch() - pass->m_aos.toMSecsSinceEpoch())
+ / (pass->m_los.toMSecsSinceEpoch() - pass->m_aos.toMSecsSinceEpoch()));
+ nowSeries->append(polarSeries->at(idx));
+ nowSeries->setPointLabelsFormat(m_settings.m_target);
+ nowSeries->setPointLabelsVisible(true);
+ nowSeries->setPointLabelsClipping(false);
+ m_polarChart->addSeries(nowSeries);
+ nowSeries->attachAxis(angularAxis);
+ nowSeries->attachAxis(radialAxis);
+ // Redraw in 5 seconds (call plotChart, incase user selects a different chart)
+ QTimer::singleShot(5000, this, &SatelliteTrackerGUI::plotChart);
+ }
+
+ delete polarSeries;
+ }
+ else
+ {
+ // Possibly geostationary, just plot current position
+ QDateTime currentTime;
+ if (m_settings.m_dateTime == "")
+ currentTime = QDateTime::currentDateTimeUtc();
+ else if (m_settings.m_utc)
+ currentTime = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
+ else
+ currentTime = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs).toUTC();
+ QString title;
+ if (m_settings.m_utc)
+ title = currentTime.date().toString(m_settings.m_dateFormat);
+ else
+ title = currentTime.toLocalTime().date().toString(m_settings.m_dateFormat);
+ m_polarChart->setTitle(QString("%1").arg(title));
+
+ QLineSeries *nowSeries = new QLineSeries();
+
+ QDateTime endTime = currentTime.addSecs(1);
+ getPassAzEl(nullptr, nullptr, nowSeries,
+ sat->m_tle->m_tle0, sat->m_tle->m_tle1, sat->m_tle->m_tle2,
+ m_settings.m_latitude, m_settings.m_longitude, m_settings.m_heightAboveSeaLevel/1000.0,
+ currentTime, endTime);
+
+ nowSeries->setPointLabelsFormat(m_settings.m_target);
+ nowSeries->setPointLabelsVisible(true);
+ nowSeries->setPointLabelsClipping(false);
+ m_polarChart->addSeries(nowSeries);
+ nowSeries->attachAxis(angularAxis);
+ nowSeries->attachAxis(radialAxis);
+ }
+
+ ui->passChart->setChart(m_polarChart);
+
+ delete oldChart;
+}
+
+// Plot target elevation/azimuth for the next pass
+void SatelliteTrackerGUI::plotAzElChart()
+{
+ if ((m_targetSatState == nullptr) || !m_satellites.contains(m_settings.m_target) || (m_targetSatState->m_passes.size() == 0))
+ {
+ ui->passChart->setChart(&m_emptyChart);
+ return;
+ }
+
+ QChart *oldChart = m_lineChart;
+
+ if (m_plotPass >= m_targetSatState->m_passes.size() - 1)
+ {
+ m_plotPass = m_targetSatState->m_passes.size() - 1;
+ ui->passLabel->setText(QString("%1").arg(m_plotPass));
+ }
+ SatellitePass *pass = m_targetSatState->m_passes[m_plotPass];
+
+ // Always create a new chart, otherwise sometimes they aren't drawn properly
+ m_lineChart = new QChart();
+ QDateTimeAxis *xAxis = new QDateTimeAxis();
+ QValueAxis *yLeftAxis = new QValueAxis();
+ QValueAxis *yRightAxis = new QValueAxis();
+
+ QString title;
+ if (m_settings.m_utc)
+ title = pass->m_aos.date().toString(m_settings.m_dateFormat);
+ else
+ title = pass->m_aos.toLocalTime().date().toString(m_settings.m_dateFormat);
+ m_lineChart->setTitle(QString("%1").arg(title));
+ m_lineChart->legend()->hide();
+ m_lineChart->addAxis(xAxis, Qt::AlignBottom);
+ m_lineChart->addAxis(yLeftAxis, Qt::AlignLeft);
+ m_lineChart->addAxis(yRightAxis, Qt::AlignRight);
+ m_lineChart->layout()->setContentsMargins(0, 0, 0, 0);
+ m_lineChart->setMargins(QMargins(1, 1, 1, 1));
+
+ SatNogsSatellite *sat = m_satellites.value(m_settings.m_target);
+
+ QLineSeries *azSeries = new QLineSeries();
+ QLineSeries *elSeries = new QLineSeries();
+
+ getPassAzEl(azSeries, elSeries, nullptr,
+ sat->m_tle->m_tle0, sat->m_tle->m_tle1, sat->m_tle->m_tle2,
+ m_settings.m_latitude, m_settings.m_longitude, m_settings.m_heightAboveSeaLevel/1000.0,
+ pass->m_aos, pass->m_los);
+
+ // Split crossing of 360/0 degrees in to multiple series in the same colour
+ QList azSeriesList;
+ QPen pen(QColor(153, 202, 83), 2, Qt::SolidLine);
+ QLineSeries *s = new QLineSeries();
+ azSeriesList.append(s);
+ s->setPen(pen);
+ qreal prevAz = azSeries->at(0).y();
+ for (int i = 0; i < azSeries->count(); i++)
+ {
+ qreal az = azSeries->at(i).y();
+ if (((prevAz >= 270) && (az < 90)) || ((prevAz < 90) && (az >= 270)))
+ {
+ s = new QLineSeries();
+ azSeriesList.append(s);
+ s->setPen(pen);
+ }
+ s->append(azSeries->at(i).x(), az);
+ prevAz = az;
+ }
+
+ m_lineChart->addSeries(elSeries);
+ elSeries->attachAxis(xAxis);
+ elSeries->attachAxis(yLeftAxis);
+ for (int i = 0; i < azSeriesList.size(); i++)
+ {
+ m_lineChart->addSeries(azSeriesList[i]);
+ azSeriesList[i]->attachAxis(xAxis);
+ azSeriesList[i]->attachAxis(yRightAxis);
+ }
+ xAxis->setRange(pass->m_aos, pass->m_los);
+ xAxis->setFormat("hh:mm");
+ yLeftAxis->setRange(0.0, 90.0);
+ yLeftAxis->setTickCount(7);
+ yLeftAxis->setLabelFormat("%d");
+ yLeftAxis->setTitleText(QString("Elevation (%1)").arg(QChar(0xb0)));
+ yRightAxis->setRange(0.0, 360.0);
+ yRightAxis->setTickCount(7);
+ yRightAxis->setLabelFormat("%d");
+ yRightAxis->setTitleText(QString("Azimuth (%1)").arg(QChar(0xb0)));
+
+ ui->passChart->setChart(m_lineChart);
+
+ delete azSeries;
+ delete oldChart;
+}
+
+void SatelliteTrackerGUI::resizeTable()
+{
+ // Fill table with a row of dummy data that will size the columns nicely
+ int row = ui->satTable->rowCount();
+ ui->satTable->setRowCount(row + 1);
+ ui->satTable->setItem(row, SAT_COL_NAME, new QTableWidgetItem("Satellite123"));
+ ui->satTable->setItem(row, SAT_COL_AZ, new QTableWidgetItem("360"));
+ ui->satTable->setItem(row, SAT_COL_EL, new QTableWidgetItem("-90"));
+ ui->satTable->setItem(row, SAT_COL_AOS, new QTableWidgetItem("+1 10:17"));
+ ui->satTable->setItem(row, SAT_COL_LOS, new QTableWidgetItem("+1 10:17"));
+ ui->satTable->setItem(row, SAT_COL_MAX_EL, new QTableWidgetItem("90"));
+ ui->satTable->setItem(row, SAT_COL_DIR, new QTableWidgetItem("^"));
+ ui->satTable->setItem(row, SAT_COL_ALT, new QTableWidgetItem("50000"));
+ ui->satTable->setItem(row, SAT_COL_RANGE, new QTableWidgetItem("50000"));
+ ui->satTable->setItem(row, SAT_COL_RANGE_RATE, new QTableWidgetItem("10.0"));
+ ui->satTable->setItem(row, SAT_COL_DOPPLER, new QTableWidgetItem("10000"));
+ ui->satTable->setItem(row, SAT_COL_PATH_LOSS, new QTableWidgetItem("100"));
+ ui->satTable->setItem(row, SAT_COL_NORAD_ID, new QTableWidgetItem("123456"));
+ ui->satTable->resizeColumnsToContents();
+ ui->satTable->setRowCount(row);
+}
+
+// As we only have limited space in table, display time plus number of days to AOS/LOS
+// unless it's greater than 10 days, in which case just display the date
+QString SatelliteTrackerGUI::formatDaysTime(qint64 days, QDateTime dateTime)
+{
+ QDateTime dt;
+ if (m_settings.m_utc)
+ dt = dateTime.toUTC();
+ else
+ dt = dateTime.toLocalTime();
+ if (abs(days) > 10)
+ return dt.date().toString(m_settings.m_dateFormat);
+ else if (days == 0)
+ return dt.time().toString("hh:mm");
+ else if (days > 0)
+ return dt.time().toString(QString("hh:mm +%1").arg(days));
+ else
+ return dt.time().toString(QString("hh:mm %1").arg(days));
+}
+
+// Table item showing some text, but sorted by datetime set as user data
+class DateTimeSortedTableWidgetItem : public QTableWidgetItem {
+public:
+ bool operator<(const QTableWidgetItem& other) const
+ {
+ QVariant v1 = data(Qt::UserRole);
+ QVariant v2 = other.data(Qt::UserRole);
+ if (v1.isValid() && v2.isValid())
+ return v1.toDateTime() < v2.toDateTime();
+ else
+ return false;
+ }
+};
+
+#define SPEED_OF_LIGHT 299792458.0
+
+// Frequency in Hz, speed in m/s
+static double doppler(double frequency, double speed)
+{
+ return frequency * speed / SPEED_OF_LIGHT;
+}
+
+// Frequency in Hz, speed in m/s
+static double freeSpaceLoss(double frequency, double distance)
+{
+ return 20.0 * log10(distance) + 20 * log10(frequency) + 20 * log10(4*M_PI/SPEED_OF_LIGHT);
+}
+
+// Distance in m, delay in s
+static double propagationDelay(double distance)
+{
+ return distance / SPEED_OF_LIGHT;
+}
+
+// Update satellite data table with latest data for the satellite
+void SatelliteTrackerGUI::updateTable(SatelliteState *satState)
+{
+ // Does the table already contain this satellite?
+ QList matches = ui->satTable->findItems(satState->m_name, Qt::MatchExactly);
+ QTableWidgetItem *items[SAT_COL_COLUMNS];
+ if (matches.size() == 0)
+ {
+ // Add a new row
+ int row = ui->satTable->rowCount();
+ ui->satTable->setRowCount(row + 1);
+ for (int i = 0; i < SAT_COL_COLUMNS; i++)
+ {
+ if ((i == SAT_COL_AOS) || (i == SAT_COL_LOS))
+ items[i] = new DateTimeSortedTableWidgetItem();
+ else
+ items[i] = new QTableWidgetItem();
+ items[i]->setToolTip(ui->satTable->horizontalHeaderItem(i)->toolTip());
+ ui->satTable->setItem(row, i, items[i]);
+ }
+ // Static columns
+ items[SAT_COL_NAME]->setText(satState->m_name);
+ if (m_satellites.contains(satState->m_name))
+ {
+ SatNogsSatellite *sat = m_satellites.value(satState->m_name);
+ items[SAT_COL_NORAD_ID]->setData(Qt::DisplayRole, sat->m_noradCatId);
+ }
+ }
+ else
+ {
+ // Update existing row
+ int row = ui->satTable->row(matches[0]);
+ for (int i = 0; i < SAT_COL_COLUMNS; i++)
+ items[i] = ui->satTable->item(row, i);
+ }
+
+ items[SAT_COL_AZ]->setData(Qt::DisplayRole, (int)round(satState->m_azimuth));
+ items[SAT_COL_EL]->setData(Qt::DisplayRole, (int)round(satState->m_elevation));
+ if (satState->m_passes.size() > 0)
+ {
+ // Get number of days to AOS/LOS
+ QDate currentDate = QDate::currentDate();
+ int daysToAOS = currentDate.daysTo(satState->m_passes[0]->m_aos.date());
+ int daysToLOS = currentDate.daysTo(satState->m_passes[0]->m_los.date());
+ items[SAT_COL_AOS]->setText(formatDaysTime(daysToAOS, satState->m_passes[0]->m_aos));
+ items[SAT_COL_AOS]->setData(Qt::UserRole, satState->m_passes[0]->m_aos);
+ items[SAT_COL_LOS]->setText(formatDaysTime(daysToLOS, satState->m_passes[0]->m_los));
+ items[SAT_COL_LOS]->setData(Qt::UserRole, satState->m_passes[0]->m_los);
+ items[SAT_COL_MAX_EL]->setData(Qt::DisplayRole, (int)round(satState->m_passes[0]->m_maxElevation));
+ if (satState->m_passes[0]->m_northToSouth)
+ items[SAT_COL_DIR]->setText(QString("%1").arg(QChar(0x2193))); // Down arrow
+ else
+ items[SAT_COL_DIR]->setText(QString("%1").arg(QChar(0x2191))); // Up arrow
+ }
+ else
+ {
+ items[SAT_COL_AOS]->setText("");
+ items[SAT_COL_LOS]->setText("");
+ items[SAT_COL_MAX_EL]->setData(Qt::DisplayRole, QVariant());
+ items[SAT_COL_DIR]->setText("");
+ }
+ items[SAT_COL_ALT]->setData(Qt::DisplayRole, (int)round(satState->m_altitude));
+ items[SAT_COL_RANGE]->setData(Qt::DisplayRole, (int)round(satState->m_range));
+ items[SAT_COL_RANGE_RATE]->setData(Qt::DisplayRole, QString::number(satState->m_rangeRate, 'f', 3));
+ items[SAT_COL_DOPPLER]->setData(Qt::DisplayRole, (int)round(-doppler(m_settings.m_defaultFrequency, satState->m_rangeRate*1000.0)));
+ items[SAT_COL_PATH_LOSS]->setData(Qt::DisplayRole, QString::number(freeSpaceLoss(m_settings.m_defaultFrequency, satState->m_range*1000.0), 'f', 1));
+ items[SAT_COL_DELAY]->setData(Qt::DisplayRole, QString::number(propagationDelay(satState->m_range*1000.0)*1000.0, 'f', 1));
+}
+
+void SatelliteTrackerGUI::on_satTable_cellDoubleClicked(int row, int column)
+{
+ (void) column;
+
+ QString sat = ui->satTable->item(row, SAT_COL_NAME)->text();
+ FeatureWebAPIUtils::mapFind(sat);
+}
+
+// Columns in table reordered
+void SatelliteTrackerGUI::satTable_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
+{
+ (void) oldVisualIndex;
+ m_settings.m_columnIndexes[logicalIndex] = newVisualIndex;
+}
+
+// Column in table resized (when hidden size is 0)
+void SatelliteTrackerGUI::satTable_sectionResized(int logicalIndex, int oldSize, int newSize)
+{
+ (void) oldSize;
+ m_settings.m_columnSizes[logicalIndex] = newSize;
+}
+
+// Right click in table header - show column select menu
+void SatelliteTrackerGUI::columnSelectMenu(QPoint pos)
+{
+ menu->popup(ui->satTable->horizontalHeader()->viewport()->mapToGlobal(pos));
+}
+
+// Hide/show column when menu selected
+void SatelliteTrackerGUI::columnSelectMenuChecked(bool checked)
+{
+ (void) checked;
+ QAction* action = qobject_cast(sender());
+ if (action != nullptr)
+ {
+ int idx = action->data().toInt(nullptr);
+ ui->satTable->setColumnHidden(idx, !action->isChecked());
+ }
+}
+
+// Create column select menu item
+QAction *SatelliteTrackerGUI::createCheckableItem(QString &text, int idx, bool checked)
+{
+ QAction *action = new QAction(text, this);
+ action->setCheckable(true);
+ action->setChecked(checked);
+ action->setData(QVariant(idx));
+ connect(action, SIGNAL(triggered()), this, SLOT(columnSelectMenuChecked()));
+ return action;
+}
diff --git a/plugins/feature/satellitetracker/satellitetrackergui.h b/plugins/feature/satellitetracker/satellitetrackergui.h
new file mode 100644
index 000000000..f355e66a7
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackergui.h
@@ -0,0 +1,154 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITETRACKERGUI_H_
+#define INCLUDE_FEATURE_SATELLITETRACKERGUI_H_
+
+#include
+#include
+#include
+#include
+
+#include "feature/featuregui.h"
+#include "util/messagequeue.h"
+#include "satellitetrackersettings.h"
+#include "satnogs.h"
+
+class PluginAPI;
+class FeatureUISet;
+class SatelliteTracker;
+struct SatelliteState;
+
+namespace Ui {
+ class SatelliteTrackerGUI;
+}
+
+using namespace QtCharts;
+
+class SatelliteTrackerGUI : public FeatureGUI {
+ Q_OBJECT
+public:
+ static SatelliteTrackerGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature);
+ virtual void destroy();
+
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+ virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+
+private:
+ Ui::SatelliteTrackerGUI* ui;
+ PluginAPI* m_pluginAPI;
+ FeatureUISet* m_featureUISet;
+ SatelliteTrackerSettings m_settings;
+ bool m_doApplySettings;
+
+ SatelliteTracker* m_satelliteTracker;
+ MessageQueue m_inputMessageQueue;
+ QTimer m_statusTimer;
+ int m_lastFeatureState;
+ bool m_lastUpdatingSatData;
+
+ QHash m_satellites;
+ SatelliteState *m_targetSatState;
+
+ int m_plotPass;
+
+ QChart m_emptyChart;
+ QChart *m_lineChart;
+ QPolarChart *m_polarChart;
+
+ QDateTime m_nextTargetAOS;
+ QDateTime m_nextTargetLOS;
+ bool m_geostationarySatVisible;
+
+ QTextToSpeech *m_speech;
+ QMenu *menu; // Column select context menu
+
+ enum SatCol {
+ SAT_COL_NAME,
+ SAT_COL_AZ,
+ SAT_COL_EL,
+ SAT_COL_AOS,
+ SAT_COL_LOS,
+ SAT_COL_MAX_EL,
+ SAT_COL_DIR,
+ SAT_COL_ALT,
+ SAT_COL_RANGE,
+ SAT_COL_RANGE_RATE,
+ SAT_COL_DOPPLER,
+ SAT_COL_PATH_LOSS,
+ SAT_COL_DELAY,
+ SAT_COL_NORAD_ID
+ };
+
+ explicit SatelliteTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
+ virtual ~SatelliteTrackerGUI();
+
+ void aos(const QString& name, int duration, int maxElevation);
+ void los(const QString& name);
+
+ void blockApplySettings(bool block);
+ void applySettings(bool force = false);
+ void displaySettings();
+ void setTarget(const QString& target);
+ QString convertDegreesToText(double degrees);
+ bool handleMessage(const Message& message);
+ void plotChart();
+ void plotAzElChart();
+ void plotPolarChart();
+ void resizeTable();
+ void updateTable(SatelliteState *satState);
+ void updateSelectedSats();
+ QAction *createCheckableItem(QString& text, int idx, bool checked);
+ void updateTimeToAOS();
+ QString formatDaysTime(qint64 days, QDateTime dateTime);
+
+ void leaveEvent(QEvent*);
+ void enterEvent(QEvent*);
+
+private slots:
+ void onMenuDialogCalled(const QPoint &p);
+ void onWidgetRolled(QWidget* widget, bool rollDown);
+ void handleInputMessages();
+ void on_startStop_toggled(bool checked);
+ void on_useMyPosition_clicked(bool checked=false);
+ void on_latitude_valueChanged(double value);
+ void on_longitude_valueChanged(double value);
+ void on_target_currentTextChanged(const QString &text);
+ void on_displaySettings_clicked();
+ void on_radioControl_clicked();
+ void on_dateTimeSelect_currentTextChanged(const QString &text);
+ void on_dateTime_dateTimeChanged(const QDateTime &datetime);
+ void updateStatus();
+ void on_viewOnMap_clicked();
+ void on_updateSatData_clicked();
+ void on_selectSats_clicked();
+ void on_autoTarget_clicked(bool checked);
+ void on_chartSelect_currentIndexChanged(int index);
+ void on_nextPass_clicked();
+ void on_prevPass_clicked();
+ void on_satTable_cellDoubleClicked(int row, int column);
+ void satTable_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
+ void satTable_sectionResized(int logicalIndex, int oldSize, int newSize);
+ void columnSelectMenu(QPoint pos);
+ void columnSelectMenuChecked(bool checked = false);
+};
+
+
+#endif // INCLUDE_FEATURE_SATELLITETRACKERGUI_H_
diff --git a/plugins/feature/satellitetracker/satellitetrackergui.ui b/plugins/feature/satellitetracker/satellitetrackergui.ui
new file mode 100644
index 000000000..ee816eca4
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackergui.ui
@@ -0,0 +1,709 @@
+
+
+ SatelliteTrackerGUI
+
+
+
+ 0
+ 0
+ 525
+ 750
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 320
+ 100
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+
+ Liberation Sans
+ 9
+
+
+
+ Satellite Tracker
+
+
+
+
+ 10
+ 10
+ 301
+ 141
+
+
+
+ Settings
+
+
+
+ 3
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+
+
+
+
+ Longitude
+
+
+
+
+
+
+ Latitude
+
+
+
+
+
+
+ Date and time to use when calculating satellite's position
+
+
+
+ Now
+
+
+
+
+ Custom
+
+
+
+
+
+
+
+ Time to acquistion of signal (AOS)
+
+
+
+
+
+
+ Time
+
+
+
+
+
+
+ Latitude in decimal degrees (North positive) of antenna location
+
+
+ 6
+
+
+ -90.000000000000000
+
+
+ 90.000000000000000
+
+
+ -90.000000000000000
+
+
+
+
+
+
+ Elevation
+
+
+
+
+
+
+ Computed azimuth in degrees to the target satellite from the antenna's location
+
+
+ 360
+
+
+ true
+
+
+
+
+
+
+ Target
+
+
+
+
+
+
+
+
+ Start/stop tracking
+
+
+
+
+
+
+ :/play.png
+ :/stop.png:/play.png
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ Find target on the map
+
+
+
+
+
+
+ :/gridpolar.png:/gridpolar.png
+
+
+
+
+
+
+ Automatically select target satellite on AOS
+
+
+ ^
+
+
+
+ :/link.png:/link.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ Update satellite data
+
+
+
+
+
+
+ :/recycle.png:/recycle.png
+
+
+
+
+
+
+ SDRangel control
+
+
+
+
+
+
+ :/sdrangel_icon.png:/sdrangel_icon.png
+
+
+
+
+
+
+ Select satellites
+
+
+
+
+
+
+ :/gps.png:/gps.png
+
+
+
+
+
+
+ Set latitude, longitude and height from My Position in SDRangel preferences
+
+
+
+
+
+
+ :/import.png:/import.png
+
+
+
+
+
+
+ Show settings dialog
+
+
+
+
+
+
+ :/listing.png:/listing.png
+
+
+
+
+
+
+
+
+ Longitude in decimal degress (East positive) of antenna location
+
+
+ 6
+
+
+ -180.000000000000000
+
+
+ 180.000000000000000
+
+
+ -180.000000000000000
+
+
+
+
+
+
+ Computed elevation in degrees to the target satellite from the antenna's location
+
+
+ 90
+
+
+ true
+
+
+
+
+
+
+ Azimuth
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Target satellite
+
+
+ -1
+
+
+
+
+
+
+ Date and time to use when calculating satellite's position
+
+
+ dd/MM/yyyy HH:mm:ss
+
+
+ true
+
+
+
+
+
+
+ AOS
+
+
+
+
+
+
+
+
+
+
+ 10
+ 160
+ 318
+ 268
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 200
+ 200
+
+
+
+ Pass Chart
+
+
+
+ 2
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+
+
+
+
+ Select type of chart to plot
+
+
+
+ Polar
+
+
+
+
+ Az/El vs Time
+
+
+
+
+
+
+
+ Plot previous pass
+
+
+ ...
+
+
+
+ :/arrow_right.png:/arrow_right.png
+
+
+
+
+
+
+ Plot next pass
+
+
+
+
+
+
+ :/arrow_left.png:/arrow_left.png
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 15
+ 0
+
+
+
+ Pass number
+
+
+ 0
+
+
+
+
+
+
+
+
+
+ 300
+ 250
+
+
+
+ Azimuth and elevation over time for satellite pass
+
+
+
+
+
+
+
+
+ 10
+ 440
+ 431
+ 291
+
+
+
+
+ 0
+ 0
+
+
+
+ Satellite Data
+
+
+
+ 2
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+
+ Satellite
+
+
+ Satellite name
+
+
+
+
+ Az
+
+
+ Azimuth in degrees to satellite from antenna location
+
+
+
+
+ El
+
+
+ Elevation in degrees to satellite from antenna location
+
+
+
+
+ AOS
+
+
+ Time of next AOS (Acquisition of signal)
+
+
+
+
+ LOS
+
+
+ Time of next LOS (Loss of signal)
+
+
+
+
+ Max El.
+
+
+ Maximum elevation in degrees of next satellite pass
+
+
+
+
+ Dir
+
+
+ Direction of the next pass
+
+
+
+
+ Alt (km)
+
+
+ Satellite altitude in kilometres
+
+
+
+
+ Range (km)
+
+
+ Range to satellite in kilometres
+
+
+
+
+ Range rate (km/s)
+
+
+ Speed of satellite towards antenna location in kilometers per second
+
+
+
+
+ Doppler (Hz)
+
+
+ Receive Doppler shift in Hertz (At frequency set in settings)
+
+
+
+
+ Path loss (dB)
+
+
+ Free space loss of signal in decibels (At frequency set in settings)
+
+
+
+
+ Delay (ms)
+
+
+ Propagation delay of a signal from the antenna to the satellite in milliseconds (assuming line-of-sight)
+
+
+
+
+ Norad ID
+
+
+ Norad catalog idenfitier for the satellite
+
+
+
+
+
+
+
+
+
+ RollupWidget
+ QWidget
+ gui/rollupwidget.h
+ 1
+
+
+ ButtonSwitch
+ QToolButton
+ gui/buttonswitch.h
+
+
+ QChartView
+ QGraphicsView
+ QtCharts
+
+
+ WrappingDateTimeEdit
+ QDateTimeEdit
+ gui/wrappingdatetimeedit.h
+ 1
+
+
+
+ startStop
+ viewOnMap
+ autoTarget
+ updateSatData
+ radioControl
+ selectSats
+ useMyPosition
+ displaySettings
+ latitude
+ longitude
+ dateTimeSelect
+ dateTime
+ target
+ aos
+ azimuth
+ elevation
+ chartSelect
+ prevPass
+ nextPass
+ passChart
+ satTable
+
+
+
+
+
+
diff --git a/plugins/feature/satellitetracker/satellitetrackerplugin.cpp b/plugins/feature/satellitetracker/satellitetrackerplugin.cpp
new file mode 100644
index 000000000..225203662
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackerplugin.cpp
@@ -0,0 +1,80 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+
+#include
+#include "plugin/pluginapi.h"
+
+#ifndef SERVER_MODE
+#include "satellitetrackergui.h"
+#endif
+#include "satellitetracker.h"
+#include "satellitetrackerplugin.h"
+#include "satellitetrackerwebapiadapter.h"
+
+const PluginDescriptor SatelliteTrackerPlugin::m_pluginDescriptor = {
+ SatelliteTracker::m_featureId,
+ QStringLiteral("Satellite Tracker"),
+ QStringLiteral("6.5.6"),
+ QStringLiteral("(c) Jon Beniston, M7RCE and Daniel Warner (SGP4 library)"),
+ QStringLiteral("https://github.com/f4exb/sdrangel"),
+ true,
+ QStringLiteral("https://github.com/f4exb/sdrangel")
+};
+
+SatelliteTrackerPlugin::SatelliteTrackerPlugin(QObject* parent) :
+ QObject(parent),
+ m_pluginAPI(nullptr)
+{
+}
+
+const PluginDescriptor& SatelliteTrackerPlugin::getPluginDescriptor() const
+{
+ return m_pluginDescriptor;
+}
+
+void SatelliteTrackerPlugin::initPlugin(PluginAPI* pluginAPI)
+{
+ m_pluginAPI = pluginAPI;
+
+ m_pluginAPI->registerFeature(SatelliteTracker::m_featureIdURI, SatelliteTracker::m_featureId, this);
+}
+
+#ifdef SERVER_MODE
+FeatureGUI* SatelliteTrackerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
+{
+ (void) featureUISet;
+ (void) feature;
+ return nullptr;
+}
+#else
+FeatureGUI* SatelliteTrackerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
+{
+ return SatelliteTrackerGUI::create(m_pluginAPI, featureUISet, feature);
+}
+#endif
+
+Feature* SatelliteTrackerPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const
+{
+ return new SatelliteTracker(webAPIAdapterInterface);
+}
+
+FeatureWebAPIAdapter* SatelliteTrackerPlugin::createFeatureWebAPIAdapter() const
+{
+ return new SatelliteTrackerWebAPIAdapter();
+}
diff --git a/plugins/feature/satellitetracker/satellitetrackerplugin.h b/plugins/feature/satellitetracker/satellitetrackerplugin.h
new file mode 100644
index 000000000..96b0e8ab5
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackerplugin.h
@@ -0,0 +1,49 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITETRACKERPLUGIN_H
+#define INCLUDE_FEATURE_SATELLITETRACKERPLUGIN_H
+
+#include
+#include "plugin/plugininterface.h"
+
+class FeatureGUI;
+class WebAPIAdapterInterface;
+
+class SatelliteTrackerPlugin : public QObject, PluginInterface {
+ Q_OBJECT
+ Q_INTERFACES(PluginInterface)
+ Q_PLUGIN_METADATA(IID "sdrangel.feature.satellitetracker")
+
+public:
+ explicit SatelliteTrackerPlugin(QObject* parent = nullptr);
+
+ const PluginDescriptor& getPluginDescriptor() const;
+ void initPlugin(PluginAPI* pluginAPI);
+
+ virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const;
+ virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const;
+ virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const;
+
+private:
+ static const PluginDescriptor m_pluginDescriptor;
+
+ PluginAPI* m_pluginAPI;
+};
+
+#endif // INCLUDE_FEATURE_SATELLITETRACKERPLUGIN_H
diff --git a/plugins/feature/satellitetracker/satellitetrackerreport.h b/plugins/feature/satellitetracker/satellitetrackerreport.h
new file mode 100644
index 000000000..8dfad0c78
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackerreport.h
@@ -0,0 +1,130 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITETRACKERREPORT_H_
+#define INCLUDE_FEATURE_SATELLITETRACKERREPORT_H_
+
+#include
+
+#include "util/message.h"
+#include "satellitetrackersgp4.h"
+
+class SatelliteTrackerReport : public QObject
+{
+ Q_OBJECT
+public:
+
+ // Sent from worker to GUI to give latest satellite data
+ class MsgReportSat : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ SatelliteState* getSatelliteState() const { return m_satState; }
+
+ static MsgReportSat* create(SatelliteState* satState)
+ {
+ return new MsgReportSat(satState);
+ }
+
+ private:
+ SatelliteState* m_satState;
+
+ MsgReportSat(SatelliteState* satState) :
+ Message(),
+ m_satState(satState)
+ {
+ }
+ };
+
+ // Sent from worker to GUI to indicate AOS
+ class MsgReportAOS : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ QString getName() const { return m_name; }
+ int getDuration() const { return m_duration; }
+ int getMaxElevation() const { return m_maxElevation; }
+
+ static MsgReportAOS* create(const QString& name, int duration, int maxElevation)
+ {
+ return new MsgReportAOS(name, duration, maxElevation);
+ }
+
+ private:
+ QString m_name;
+ int m_duration;
+ int m_maxElevation;
+
+ MsgReportAOS(const QString& name, int duration, int maxElevation) :
+ Message(),
+ m_name(name),
+ m_duration(duration),
+ m_maxElevation(maxElevation)
+ {
+ }
+ };
+
+ // Sent from worker to GUI to indicaite LOS
+ class MsgReportLOS : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ QString getName() const { return m_name; }
+
+ static MsgReportLOS* create(const QString& name)
+ {
+ return new MsgReportLOS(name);
+ }
+
+ private:
+ QString m_name;
+
+ MsgReportLOS(const QString& name) :
+ Message(),
+ m_name(name)
+ {
+ }
+ };
+
+ // Sent from worker to GUI, to indicate target has changed
+ class MsgReportTarget : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ QString getName() const { return m_name; }
+
+ static MsgReportTarget* create(const QString& name)
+ {
+ return new MsgReportTarget(name);
+ }
+
+ private:
+ QString m_name;
+
+ MsgReportTarget(const QString& name) :
+ Message(),
+ m_name(name)
+ {
+ }
+ };
+
+public:
+ SatelliteTrackerReport() {}
+ ~SatelliteTrackerReport() {}
+};
+
+#endif // INCLUDE_FEATURE_SATELLITETRACKERREPORT_H_
diff --git a/plugins/feature/satellitetracker/satellitetrackersettings.cpp b/plugins/feature/satellitetracker/satellitetrackersettings.cpp
new file mode 100644
index 000000000..53fe10f14
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackersettings.cpp
@@ -0,0 +1,300 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+#include "util/simpleserializer.h"
+#include "settings/serializable.h"
+
+#include "satellitetrackersettings.h"
+
+#define DEAFULT_TARGET "ISS"
+#define DEFAULT_TLES {"https://db.satnogs.org/api/tle/", "https://www.amsat.org/tle/current/nasabare.txt", "https://www.celestrak.com/NORAD/elements/goes.txt"}
+#define DEFAULT_DATE_FORMAT "yyyy/MM/dd"
+#define DEFAULT_AOS_SPEECH "${name} is visible for ${duration} minutes. Max elevation, ${elevation} degrees."
+#define DEFAULT_LOS_SPEECH "${name} is no longer visible."
+
+SatelliteTrackerSettings::SatelliteTrackerSettings()
+{
+ resetToDefaults();
+}
+
+void SatelliteTrackerSettings::resetToDefaults()
+{
+ m_latitude = 0.0;
+ m_longitude = 0.0;
+ m_heightAboveSeaLevel = 0.0;
+ m_target = DEAFULT_TARGET;
+ m_satellites = {QString(DEAFULT_TARGET)};
+ m_tles = DEFAULT_TLES;
+ m_dateTime = "";
+ m_minAOSElevation = 5;
+ m_minPassElevation = 15;
+ m_rotatorMaxAzimuth = 450;
+ m_rotatorMaxElevation = 180;
+ m_azElUnits = DM;
+ m_groundTrackPoints = 100;
+ m_dateFormat = DEFAULT_DATE_FORMAT;
+ m_utc = false;
+ m_updatePeriod = 1.0f;
+ m_dopplerPeriod = 10.0f;
+ m_defaultFrequency = 100000000.0f;
+ m_drawOnMap = true;
+ m_autoTarget = true;
+ m_aosSpeech = DEFAULT_AOS_SPEECH;
+ m_losSpeech = DEFAULT_LOS_SPEECH;
+ m_aosCommand = "";
+ m_losCommand = "";
+ m_predictionPeriod = 5;
+ m_passStartTime = QTime(0,0);
+ m_passFinishTime = QTime(23,59,59);
+ m_title = "Satellite Tracker";
+ m_rgbColor = QColor(225, 25, 99).rgb();
+ m_useReverseAPI = false;
+ m_reverseAPIAddress = "127.0.0.1";
+ m_reverseAPIPort = 8888;
+ m_reverseAPIFeatureSetIndex = 0;
+ m_reverseAPIFeatureIndex = 0;
+ for (int i = 0; i < SAT_COL_COLUMNS; i++)
+ {
+ m_columnIndexes[i] = i;
+ m_columnSizes[i] = -1; // Autosize
+ }
+}
+
+QByteArray SatelliteTrackerSettings::serialize() const
+{
+ SimpleSerializer s(1);
+
+ s.writeDouble(1, m_latitude);
+ s.writeDouble(2, m_longitude);
+ s.writeDouble(3, m_heightAboveSeaLevel);
+ s.writeString(4, m_target);
+ s.writeBlob(5, serializeStringList(m_satellites));
+ s.writeBlob(6, serializeStringList(m_tles));
+ s.writeString(7, m_dateTime);
+ s.writeS32(8, m_minAOSElevation);
+ s.writeS32(9, m_minPassElevation);
+ s.writeS32(10, m_rotatorMaxAzimuth);
+ s.writeS32(11, m_rotatorMaxElevation);
+ s.writeS32(12, m_azElUnits);
+ s.writeS32(13, m_groundTrackPoints);
+ s.writeString(14, m_dateFormat);
+ s.writeBool(15, m_utc);
+ s.writeFloat(16, m_updatePeriod);
+ s.writeFloat(17, m_dopplerPeriod);
+ s.writeS32(18, m_predictionPeriod);
+ s.writeString(19, m_passStartTime.toString());
+ s.writeString(20, m_passFinishTime.toString());
+ s.writeFloat(21, m_defaultFrequency);
+ s.writeBool(22, m_drawOnMap);
+ s.writeBool(23, m_autoTarget);
+ s.writeString(24, m_aosSpeech);
+ s.writeString(25, m_losSpeech);
+ s.writeString(26, m_aosCommand);
+ s.writeString(27, m_losCommand);
+ s.writeBlob(28, serializeDeviceSettings(m_deviceSettings));
+
+ s.writeString(29, m_title);
+ s.writeU32(30, m_rgbColor);
+ s.writeBool(31, m_useReverseAPI);
+ s.writeString(32, m_reverseAPIAddress);
+ s.writeU32(33, m_reverseAPIPort);
+ s.writeU32(34, m_reverseAPIFeatureSetIndex);
+ s.writeU32(35, m_reverseAPIFeatureIndex);
+
+ for (int i = 0; i < SAT_COL_COLUMNS; i++)
+ s.writeS32(100 + i, m_columnIndexes[i]);
+ for (int i = 0; i < SAT_COL_COLUMNS; i++)
+ s.writeS32(200 + i, m_columnSizes[i]);
+
+ return s.final();
+}
+
+bool SatelliteTrackerSettings::deserialize(const QByteArray& data)
+{
+ SimpleDeserializer d(data);
+
+ if (!d.isValid())
+ {
+ resetToDefaults();
+ return false;
+ }
+
+ if (d.getVersion() == 1)
+ {
+ QByteArray bytetmp;
+ uint32_t utmp;
+ QString strtmp;
+ QByteArray blob;
+
+ d.readDouble(1, &m_latitude, 0.0);
+ d.readDouble(2, &m_longitude, 0.0);
+ d.readDouble(3, &m_heightAboveSeaLevel, 0.0);
+ d.readString(4, &m_target, DEAFULT_TARGET);
+ d.readBlob(5, &blob);
+ deserializeStringList(blob, m_satellites);
+ d.readBlob(6, &blob);
+ deserializeStringList(blob, m_tles);
+ d.readString(7, &m_dateTime, "");
+ d.readS32(8, &m_minAOSElevation, 5);
+ d.readS32(9, &m_minPassElevation, 15);
+ d.readS32(10, &m_rotatorMaxAzimuth, 450);
+ d.readS32(11, &m_rotatorMaxElevation, 180);
+ d.readS32(12, (qint32 *)&m_azElUnits, DM);
+ d.readS32(13, &m_groundTrackPoints, 100);
+ d.readString(14, &m_dateFormat, DEFAULT_DATE_FORMAT);
+ d.readBool(15, &m_utc, false);
+ d.readFloat(16, &m_updatePeriod, 1.0f);
+ d.readFloat(17, &m_dopplerPeriod, 10.0f);
+ d.readS32(18, &m_predictionPeriod, 5);
+ d.readString(19, &strtmp, "00:00:00");
+ m_passStartTime = QTime::fromString(strtmp);
+ d.readString(20, &strtmp, "23:59:59");
+ m_passFinishTime = QTime::fromString(strtmp);
+ d.readFloat(21, &m_defaultFrequency, 100000000.0f);
+ d.readBool(22, &m_drawOnMap, true);
+ d.readBool(23, &m_autoTarget, true);
+ d.readString(24, &m_aosSpeech, DEFAULT_AOS_SPEECH);
+ d.readString(25, &m_aosCommand, DEFAULT_LOS_SPEECH);
+ d.readString(26, &m_aosCommand, "");
+ d.readString(27, &m_losCommand, "");
+ d.readBlob(28, &blob);
+ deserializeDeviceSettings(blob, m_deviceSettings);
+
+ d.readString(29, &m_title, "Satellite Tracker");
+ d.readU32(30, &m_rgbColor, QColor(225, 25, 99).rgb());
+ d.readBool(31, &m_useReverseAPI, false);
+ d.readString(32, &m_reverseAPIAddress, "127.0.0.1");
+ d.readU32(33, &utmp, 0);
+
+ if ((utmp > 1023) && (utmp < 65535)) {
+ m_reverseAPIPort = utmp;
+ } else {
+ m_reverseAPIPort = 8888;
+ }
+
+ d.readU32(34, &utmp, 0);
+ m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp;
+ d.readU32(35, &utmp, 0);
+ m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
+
+ for (int i = 0; i < SAT_COL_COLUMNS; i++)
+ d.readS32(100 + i, &m_columnIndexes[i], i);
+ for (int i = 0; i < SAT_COL_COLUMNS; i++)
+ d.readS32(200 + i, &m_columnSizes[i], -1);
+
+ return true;
+ }
+ else
+ {
+ resetToDefaults();
+ return false;
+ }
+}
+
+QByteArray SatelliteTrackerSettings::serializeStringList(const QList& strings) const
+{
+ QByteArray data;
+ QDataStream *stream = new QDataStream(&data, QIODevice::WriteOnly);
+ (*stream) << strings;
+ delete stream;
+ return data;
+}
+
+void SatelliteTrackerSettings::deserializeStringList(const QByteArray& data, QList& strings)
+{
+ QDataStream *stream = new QDataStream(data);
+ (*stream) >> strings;
+ delete stream;
+}
+
+QDataStream& operator<<(QDataStream& out, const QList *list)
+{
+ out << *list;
+ return out;
+}
+
+QDataStream& operator>>(QDataStream& in, QList*& list)
+{
+ list = new QList();
+ in >> *list;
+ return in;
+}
+
+QDataStream& operator<<(QDataStream& out, const SatelliteTrackerSettings::SatelliteDeviceSettings* settings)
+{
+ out << settings->m_deviceSet;
+ out << settings->m_presetGroup;
+ out << settings->m_presetFrequency;
+ out << settings->m_presetDescription;
+ out << settings->m_doppler;
+ out << settings->m_startOnAOS;
+ out << settings->m_stopOnLOS;
+ out << settings->m_startStopFileSink;
+ out << settings->m_frequency;
+ out << settings->m_aosCommand;
+ out << settings->m_losCommand;
+ return out;
+}
+
+QDataStream& operator>>(QDataStream& in, SatelliteTrackerSettings::SatelliteDeviceSettings*& settings)
+{
+ settings = new SatelliteTrackerSettings::SatelliteDeviceSettings();
+ in >> settings->m_deviceSet;
+ in >> settings->m_presetGroup;
+ in >> settings->m_presetFrequency;
+ in >> settings->m_presetDescription;
+ in >> settings->m_doppler;
+ in >> settings->m_startOnAOS;
+ in >> settings->m_stopOnLOS;
+ in >> settings->m_startStopFileSink;
+ in >> settings->m_frequency;
+ in >> settings->m_aosCommand;
+ in >> settings->m_losCommand;
+ return in;
+}
+
+QByteArray SatelliteTrackerSettings::serializeDeviceSettings(QHash *> deviceSettings) const
+{
+ QByteArray data;
+ QDataStream *stream = new QDataStream(&data, QIODevice::WriteOnly);
+ (*stream) << deviceSettings;
+ delete stream;
+ return data;
+}
+
+void SatelliteTrackerSettings::deserializeDeviceSettings(const QByteArray& data, QHash *>& deviceSettings)
+{
+ QDataStream *stream = new QDataStream(data);
+ (*stream) >> deviceSettings;
+ delete stream;
+}
+
+SatelliteTrackerSettings::SatelliteDeviceSettings::SatelliteDeviceSettings()
+{
+ m_deviceSet = "R0";
+ m_presetFrequency = 0;
+ m_startOnAOS = true;
+ m_stopOnLOS = true;
+ m_startStopFileSink = true;
+ m_frequency = 0;
+ m_aosCommand = "";
+ m_losCommand = "";
+}
diff --git a/plugins/feature/satellitetracker/satellitetrackersettings.h b/plugins/feature/satellitetracker/satellitetrackersettings.h
new file mode 100644
index 000000000..6caa0bdd9
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackersettings.h
@@ -0,0 +1,100 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITETRACKERSETTINGS_H_
+#define INCLUDE_FEATURE_SATELLITETRACKERSETTINGS_H_
+
+#include
+#include
+#include
+#include
+#include
+
+class Serializable;
+
+#define SAT_COL_COLUMNS 14
+
+struct SatelliteTrackerSettings
+{
+ struct SatelliteDeviceSettings
+ {
+ QString m_deviceSet; //!< R0, T1...
+ QString m_presetGroup; //!< Preset to load to device set
+ quint64 m_presetFrequency;
+ QString m_presetDescription;
+ QList m_doppler; //!< Which channels to apply Doppler correction to, if any
+ bool m_startOnAOS; //!< Start acquistion on AOS
+ bool m_stopOnLOS; //!< Stop acquistion on LOS
+ bool m_startStopFileSink; //!< Start&stop file sinks recording on AOS/LOS
+ quint64 m_frequency; //!< Optional center frequency to set (in Hz), to override preset value
+ QString m_aosCommand; //!< Command/script to execute on AOS
+ QString m_losCommand; //!< Command/script to execute on LOS
+ SatelliteDeviceSettings();
+ };
+
+ double m_latitude; //!< Antenna location, degrees
+ double m_longitude;
+ double m_heightAboveSeaLevel; //!< In metres
+ QString m_target; //!< Target satellite
+ QList m_satellites; //!< Selected satellites
+ QList m_tles; //!< TLE URLs
+ QString m_dateTime; //!< Date/time for observation, or "" for now (UTC or local as per m_utc)
+ int m_minAOSElevation; //!< Minimum elevation for AOS
+ int m_minPassElevation; //!< Minimum elevation for a pass
+ int m_rotatorMaxAzimuth; //!< Maximum rotator azimuth 360/450
+ int m_rotatorMaxElevation; //!< Maximum rotator elevation 90/180
+ enum AzElUnits {DMS, DM, D, Decimal} m_azElUnits;
+ int m_groundTrackPoints; //!< Number of points in ground tracks
+ QString m_dateFormat; //!< Format used for displaying dates in the GUI
+ bool m_utc; //!< Set/display times as UTC rather than local
+ float m_updatePeriod; //!< How long in seconds between updates of satellite's position
+ float m_dopplerPeriod; //!< How long in seconds between Doppler corrections
+ int m_predictionPeriod; //!< How many days ahead to predict passes in
+ QTime m_passStartTime; //!< Time after which pass must start
+ QTime m_passFinishTime; //!< Time before which pass must finish
+ float m_defaultFrequency; //!< Frequency used for Doppler & path loss calculation in satellite table
+ bool m_drawOnMap;
+ bool m_autoTarget; //!< Automatically select target on AOS
+ QString m_aosSpeech; //!< Text to say on AOS
+ QString m_losSpeech; //!< Text to say on LOS
+ QString m_aosCommand; //!< Command/script to execute on AOS
+ QString m_losCommand; //!< Command/script to execute on LOS
+ QHash *> m_deviceSettings; //!< Settings for each device set for each satellite
+
+ int m_columnIndexes[SAT_COL_COLUMNS];//!< How the columns are ordered in the table
+ int m_columnSizes[SAT_COL_COLUMNS]; //!< Size of the coumns in the table
+
+ QString m_title;
+ quint32 m_rgbColor;
+ bool m_useReverseAPI;
+ QString m_reverseAPIAddress;
+ uint16_t m_reverseAPIPort;
+ uint16_t m_reverseAPIFeatureSetIndex;
+ uint16_t m_reverseAPIFeatureIndex;
+
+ SatelliteTrackerSettings();
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+ QByteArray serializeStringList(const QList& strings) const;
+ void deserializeStringList(const QByteArray& data, QList& strings);
+ QByteArray serializeDeviceSettings(QHash *> deviceSettings) const;
+ void deserializeDeviceSettings(const QByteArray& data, QHash *>& deviceSettings);
+};
+
+#endif // INCLUDE_FEATURE_SATELLITETRACKERSETTINGS_H_
diff --git a/plugins/feature/satellitetracker/satellitetrackersettingsdialog.cpp b/plugins/feature/satellitetracker/satellitetrackersettingsdialog.cpp
new file mode 100644
index 000000000..c1e53b568
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackersettingsdialog.cpp
@@ -0,0 +1,97 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "satellitetrackersettingsdialog.h"
+#include
+
+SatelliteTrackerSettingsDialog::SatelliteTrackerSettingsDialog(SatelliteTrackerSettings *settings,
+ QWidget* parent) :
+ QDialog(parent),
+ m_settings(settings),
+ ui(new Ui::SatelliteTrackerSettingsDialog)
+{
+ ui->setupUi(this);
+ ui->height->setValue(settings->m_heightAboveSeaLevel);
+ ui->predictionPeriod->setValue(settings->m_predictionPeriod);
+ ui->passStartTime->setTime(settings->m_passStartTime);
+ ui->passFinishTime->setTime(settings->m_passFinishTime);
+ ui->minimumAOSElevation->setValue(settings->m_minAOSElevation);
+ ui->minimumPassElevation->setValue(settings->m_minPassElevation);
+ ui->aosSpeech->setText(settings->m_aosSpeech);
+ ui->losSpeech->setText(settings->m_losSpeech);
+ ui->aosCommand->setText(settings->m_aosCommand);
+ ui->losCommand->setText(settings->m_losCommand);
+ ui->updatePeriod->setValue(settings->m_updatePeriod);
+ ui->dopplerPeriod->setValue(settings->m_dopplerPeriod);
+ ui->defaultFrequency->setValue(settings->m_defaultFrequency / 1000000.0);
+ ui->azElUnits->setCurrentIndex((int)settings->m_azElUnits);
+ ui->groundTrackPoints->setValue(settings->m_groundTrackPoints);
+ ui->dateFormat->setText(settings->m_dateFormat);
+ ui->utc->setChecked(settings->m_utc);
+ ui->drawOnMap->setChecked(settings->m_drawOnMap);
+ for (int i = 0; i < settings->m_tles.size(); i++)
+ {
+ QListWidgetItem *item = new QListWidgetItem(settings->m_tles[i]);
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
+ ui->tles->addItem(item);
+ }
+}
+
+SatelliteTrackerSettingsDialog::~SatelliteTrackerSettingsDialog()
+{
+ delete ui;
+}
+
+void SatelliteTrackerSettingsDialog::on_addTle_clicked()
+{
+ QListWidgetItem *item = new QListWidgetItem("http://");
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
+ ui->tles->addItem(item);
+}
+
+void SatelliteTrackerSettingsDialog::on_removeTle_clicked()
+{
+ QList items = ui->tles->selectedItems();
+ for (int i = 0; i < items.size(); i++)
+ delete items[i];
+}
+
+void SatelliteTrackerSettingsDialog::accept()
+{
+ m_settings->m_heightAboveSeaLevel = ui->height->value();
+ m_settings->m_predictionPeriod = ui->predictionPeriod->value();
+ m_settings->m_passStartTime = ui->passStartTime->time();
+ m_settings->m_passFinishTime = ui->passFinishTime->time();
+ m_settings->m_minAOSElevation = ui->minimumAOSElevation->value();
+ m_settings->m_minPassElevation = ui->minimumPassElevation->value();
+ m_settings->m_aosSpeech = ui->aosSpeech->text();
+ m_settings->m_losSpeech = ui->losSpeech->text();
+ m_settings->m_aosCommand = ui->aosCommand->text();
+ m_settings->m_losCommand = ui->losCommand->text();
+ m_settings->m_updatePeriod = (float)ui->updatePeriod->value();
+ m_settings->m_dopplerPeriod = (float)ui->dopplerPeriod->value();
+ m_settings->m_defaultFrequency = (float)(ui->defaultFrequency->value() * 1000000.0);
+ m_settings->m_azElUnits = (SatelliteTrackerSettings::AzElUnits)ui->azElUnits->currentIndex();
+ m_settings->m_groundTrackPoints = ui->groundTrackPoints->value();
+ m_settings->m_dateFormat = ui->dateFormat->text();
+ m_settings->m_utc = ui->utc->isChecked();
+ m_settings->m_drawOnMap = ui->drawOnMap->isChecked();
+ m_settings->m_tles.clear();
+ for (int i = 0; i < ui->tles->count(); i++)
+ m_settings->m_tles.append(ui->tles->item(i)->text());
+ QDialog::accept();
+}
diff --git a/plugins/feature/satellitetracker/satellitetrackersettingsdialog.h b/plugins/feature/satellitetracker/satellitetrackersettingsdialog.h
new file mode 100644
index 000000000..da8e3a111
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackersettingsdialog.h
@@ -0,0 +1,42 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_SATELLITETRACKERSETTINGSDIALOG_H
+#define INCLUDE_SATELLITETRACKERSETTINGSDIALOG_H
+
+#include "ui_satellitetrackersettingsdialog.h"
+#include "satellitetrackersettings.h"
+
+class SatelliteTrackerSettingsDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit SatelliteTrackerSettingsDialog(SatelliteTrackerSettings* settings, QWidget* parent = 0);
+ ~SatelliteTrackerSettingsDialog();
+
+ SatelliteTrackerSettings *m_settings;
+
+private slots:
+ void on_addTle_clicked();
+ void on_removeTle_clicked();
+ void accept();
+
+private:
+ Ui::SatelliteTrackerSettingsDialog* ui;
+};
+
+#endif // INCLUDE_SATELLITETRACKERSETTINGSDIALOG_H
diff --git a/plugins/feature/satellitetracker/satellitetrackersettingsdialog.ui b/plugins/feature/satellitetracker/satellitetrackersettingsdialog.ui
new file mode 100644
index 000000000..08d13515b
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackersettingsdialog.ui
@@ -0,0 +1,576 @@
+
+
+ SatelliteTrackerSettingsDialog
+
+
+
+ 0
+ 0
+ 487
+ 543
+
+
+
+
+ Liberation Sans
+ 9
+
+
+
+ Satellite Tracker Settings
+
+
+
+
+
+
+
+
+ 0
+
+
+
+ Passes
+
+
+
+
+
+ Antenna height (m ASL)
+
+
+
+
+
+
+ Height of antenna location above sea level in metres
+
+
+ -1000
+
+
+ 20000
+
+
+
+
+
+
+ Number of days ahead for which passes should be predicted in
+
+
+ 1
+
+
+ 365
+
+
+
+
+
+
+ Minimum elevation for AOS (°)
+
+
+
+
+
+
+ Enter a minimum elevation in degrees for which AOS (Acquisition of Signal) will be indicated
+
+
+ -90
+
+
+ 90
+
+
+
+
+
+
+ Minimum elevation for pass (°)
+
+
+
+
+
+
+ Enter a minimum elevation in degrees a satellite must reach in a pass
+
+
+ 90
+
+
+
+
+
+
+ Passes must start after
+
+
+
+
+
+
+
+
+
+ Passes must finish before
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rotator maximum azimuth (°)
+
+
+
+
+
+
+ Maximum azimuth angle of rotator in degrees
+
+
+ 360
+
+
+ 720
+
+
+ 90
+
+
+ 450
+
+
+
+
+
+
+ Rotator maximum elevation (°)
+
+
+
+
+
+
+ Maximum elevation angle of rotator in degrees
+
+
+ 180
+
+
+ 90
+
+
+ 180
+
+
+
+
+
+
+ AOS speech warning
+
+
+
+
+
+
+ Text to say when a satellite signal is acquired
+
+
+
+
+
+
+ LOS speech warning
+
+
+
+
+
+
+ Text to say when a satellite signal is lost
+
+
+
+
+
+
+ AOS command
+
+
+
+
+
+
+ Program / script to execute on AOS
+
+
+
+
+
+
+ LOS command
+
+
+
+
+
+
+ Program / script to execute on LOS
+
+
+
+
+
+
+ Doppler period (s)
+
+
+
+
+
+
+ Enter the time in seconds between each Doppler correction
+
+
+ 0.010000000000000
+
+
+ 100.000000000000000
+
+
+ 10.000000000000000
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+ Prediction period (days)
+
+
+
+
+
+
+
+ TLEs
+
+
+
+
+
+ Satellite Two Line Element (TLE) sources
+
+
+ QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked
+
+
+
+
+
+
+
+
+ Add TLE
+
+
+ +
+
+
+
+
+
+
+ Remove selected TLE
+
+
+ -
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+ Display
+
+
+
+
+
+ Frequency used for Doppler and free space path loss calculations in the satellite table
+
+
+ 3
+
+
+ 1.000000000000000
+
+
+ 50000.000000000000000
+
+
+ 100.000000000000000
+
+
+ 100.000000000000000
+
+
+
+
+
+
+ Format for dates displayed in the GUI
+
+
+
+
+
+
+ When checked satellite positions are sent to the map
+
+
+ Draw satellites on map
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+ Update period (s)
+
+
+
+
+
+
+ Enter the time in seconds between each calculation of the target's position
+
+
+ 3600.000000000000000
+
+
+ 1.000000000000000
+
+
+
+
+
+
+ Default frequency (MHz)
+
+
+
+
+
+
+ Units used for displaying azimuth and elevation. Either degrees, minutes and seconds or decimal degrees.
+
+
+ false
+
+
+
+ ° ' "
+
+
+
+
+ ° '
+
+
+
+
+ °
+
+
+
+
+ Decimal
+
+
+
+
+
+
+
+ Azimuth and elevation units
+
+
+
+
+
+
+ When checked times are dispayed using UTC rather than the local time zone
+
+
+ Display times in UTC
+
+
+
+
+
+
+ Date format
+
+
+
+
+
+
+ Ground track points
+
+
+
+
+
+
+ Number of points in ground tracks (more points result in smoother curves)
+
+
+ 10
+
+
+ 360
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+ tabWidget
+ height
+ predictionPeriod
+ minimumAOSElevation
+ minimumPassElevation
+ passStartTime
+ passFinishTime
+ rotatorMaximumAzimuth
+ rotatorMaximumElevation
+ aosSpeech
+ losSpeech
+ aosCommand
+ losCommand
+ dopplerPeriod
+ tles
+ addTle
+ removeTle
+ updatePeriod
+ defaultFrequency
+ azElUnits
+ groundTrackPoints
+ dateFormat
+ utc
+ drawOnMap
+
+
+
+
+ buttonBox
+ accepted()
+ SatelliteTrackerSettingsDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ SatelliteTrackerSettingsDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/plugins/feature/satellitetracker/satellitetrackersgp4.cpp b/plugins/feature/satellitetracker/satellitetrackersgp4.cpp
new file mode 100644
index 000000000..c61b0cb17
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackersgp4.cpp
@@ -0,0 +1,497 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2013 Daniel Warner //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "util/units.h"
+
+#include "satellitetrackersgp4.h"
+
+// Convert QGP4 DateTime to Qt QDataTime
+static QDateTime dateTimeToQDateTime(DateTime dt)
+{
+ QDateTime qdt(QDate(dt.Year(), dt.Month(), dt.Day()), QTime(dt.Hour(), dt.Minute(), dt.Second(), (int)(dt.Microsecond()/1000.0)), Qt::UTC);
+ return qdt;
+}
+
+// Convert Qt QDataTime to QGP4 DateTime
+static DateTime qDateTimeToDateTime(QDateTime qdt)
+{
+ QDateTime utc = qdt.toUTC();
+ QDate date = utc.date();
+ QTime time = utc.time();
+ DateTime dt(date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second());
+ return dt;
+}
+
+// Get ground track
+// Throws SatelliteException, DecayedException and TleException
+void getGroundTrack(QDateTime dateTime,
+ const QString& tle0, const QString& tle1, const QString& tle2,
+ int steps, bool forward,
+ QList& coordinates)
+{
+ Tle tle = Tle(tle0.toStdString(), tle1.toStdString(), tle2.toStdString());
+ SGP4 sgp4(tle);
+ OrbitalElements ele(tle);
+ double periodMins;
+ double timeStep;
+
+ // Note map doesn't support paths wrapping around Earth
+ DateTime currentTime = qDateTimeToDateTime(dateTime);
+ DateTime endTime;
+ if (forward)
+ {
+ periodMins = ele.Period() * 0.9;
+ endTime = currentTime.AddMinutes(periodMins);
+ timeStep = periodMins / (steps * 0.9);
+ }
+ else
+ {
+ periodMins = ele.Period() * 0.4;
+ endTime = currentTime.AddMinutes(-periodMins);
+ timeStep = -periodMins / (steps * 0.4);
+ }
+
+ coordinates.clear();
+ while ((forward && (currentTime < endTime)) || (!forward && (currentTime > endTime)))
+ {
+ // Calculate satellite position
+ Eci eci = sgp4.FindPosition(currentTime);
+
+ // Convert satellite position to geodetic coordinates (lat and long)
+ CoordGeodetic geo = eci.ToGeodetic();
+
+ QGeoCoordinate *coord = new QGeoCoordinate(Units::radiansToDegrees(geo.latitude),
+ Units::radiansToDegrees(geo.longitude),
+ geo.altitude * 1000.0);
+ coordinates.append(coord);
+ // Map is stretched at poles, so use finer steps
+ if (std::abs(Units::radiansToDegrees(geo.latitude)) >= 70)
+ currentTime = currentTime.AddMinutes(timeStep/4);
+ else
+ currentTime = currentTime.AddMinutes(timeStep);
+ }
+}
+
+// Find azimuth and elevation points during a pass
+void getPassAzEl(QLineSeries* azimuth, QLineSeries* elevation, QLineSeries* polar,
+ const QString& tle0, const QString& tle1, const QString& tle2,
+ double latitude, double longitude, double altitude,
+ QDateTime& aos, QDateTime& los)
+{
+ try
+ {
+ Tle tle = Tle(tle0.toStdString(), tle1.toStdString(), tle2.toStdString());
+ SGP4 sgp4(tle);
+ Observer obs(latitude, longitude, altitude);
+
+ DateTime aosTime = qDateTimeToDateTime(aos);
+ DateTime losTime = qDateTimeToDateTime(los);
+ DateTime currentTime(aosTime);
+ int steps = 20;
+
+ double timeStep = (losTime - aosTime).TotalSeconds() / steps;
+
+ while (currentTime <= losTime)
+ {
+ // Calculate satellite position
+ Eci eci = sgp4.FindPosition(currentTime);
+
+ // Calculate angle to satellite from antenna
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+
+ // Save azimuth and elevation in series
+ QDateTime qdt = dateTimeToQDateTime(currentTime);
+ if (azimuth != nullptr)
+ azimuth->append(qdt.toMSecsSinceEpoch(), Units::radiansToDegrees(topo.azimuth));
+ if (elevation != nullptr)
+ elevation->append(qdt.toMSecsSinceEpoch(), Units::radiansToDegrees(topo.elevation));
+ if (polar != nullptr)
+ polar->append(Units::radiansToDegrees(topo.azimuth), 90.0-Units::radiansToDegrees(topo.elevation));
+
+ currentTime = currentTime.AddSeconds(timeStep);
+ }
+ }
+ catch (SatelliteException& se)
+ {
+ qDebug() << se.what();
+ }
+ catch (DecayedException& de)
+ {
+ qDebug() << de.what();
+ }
+ catch (TleException& tlee)
+ {
+ qDebug() << tlee.what();
+ }
+}
+
+// Get whether a pass passes through 0 degreees
+bool getPassesThrough0Deg(const QString& tle0, const QString& tle1, const QString& tle2,
+ double latitude, double longitude, double altitude,
+ QDateTime& aos, QDateTime& los)
+{
+ try
+ {
+ Tle tle = Tle(tle0.toStdString(), tle1.toStdString(), tle2.toStdString());
+ SGP4 sgp4(tle);
+ Observer obs(latitude, longitude, altitude);
+
+ DateTime aosTime = qDateTimeToDateTime(aos);
+ DateTime losTime = qDateTimeToDateTime(los);
+ DateTime currentTime(aosTime);
+ int steps = 20;
+
+ double timeStep = (losTime - aosTime).TotalSeconds() / steps;
+
+ double prevAz;
+ for (int i = 0; i < steps; i++)
+ {
+ // Calculate satellite position
+ Eci eci = sgp4.FindPosition(currentTime);
+
+ // Calculate angle to satellite from antenna
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+
+ double az = Units::radiansToDegrees(topo.azimuth);
+ if (i == 0)
+ prevAz = az;
+
+ // Does it cross 0 degrees?
+ if (((prevAz > 270.0) && (az < 90.0)) || ((prevAz < 90.0) && (az >= 270.0)))
+ return true;
+
+ prevAz = az;
+ currentTime = currentTime.AddSeconds(timeStep);
+ }
+ }
+ catch (SatelliteException& se)
+ {
+ qDebug() << se.what();
+ }
+ catch (DecayedException& de)
+ {
+ qDebug() << de.what();
+ }
+ catch (TleException& tlee)
+ {
+ qDebug() << tlee.what();
+ }
+ return false;
+}
+
+// Find maximum elevation in a pass
+static double findMaxElevation(Observer& obs1, SGP4& sgp4, const DateTime& aos, const DateTime& los)
+{
+ Observer obs(obs1.GetLocation());
+ bool running;
+ double timeStep = (los - aos).TotalSeconds() / 9.0;
+ DateTime currentTime(aos);
+ DateTime time1(aos);
+ DateTime time2(los);
+ double maxElevation;
+
+ do
+ {
+ running = true;
+ maxElevation = -INFINITY;
+ while (running && (currentTime < time2))
+ {
+ Eci eci = sgp4.FindPosition(currentTime);
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+ if (topo.elevation > maxElevation)
+ {
+ maxElevation = topo.elevation;
+ currentTime = currentTime.AddSeconds(timeStep);
+ if (currentTime > time2)
+ currentTime = time2;
+ }
+ else
+ running = false;
+ }
+ time1 = currentTime.AddSeconds(-2.0 * timeStep);
+ time2 = currentTime;
+ currentTime = time1;
+ timeStep = (time2 - time1).TotalSeconds() / 9.0;
+ }
+ while (timeStep > 1.0);
+
+ return Units::radiansToDegrees(maxElevation);
+}
+
+// Find the time at which the satellite crossed the minimum elevation required for AOS or LOS
+static DateTime findCrossingPoint(Observer& obs, SGP4& sgp4, const DateTime& initialTime1, const DateTime& initialTime2, double minElevation, bool findingAOS)
+{
+ bool running;
+ int cnt;
+ DateTime time1(initialTime1);
+ DateTime time2(initialTime2);
+ DateTime middleTime;
+
+ running = true;
+ cnt = 0;
+ while (running && (cnt++ < 16))
+ {
+ middleTime = time1.AddSeconds((time2 - time1).TotalSeconds() / 2.0);
+ Eci eci = sgp4.FindPosition(middleTime);
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+ if (topo.elevation > minElevation)
+ {
+ if (findingAOS)
+ time2 = middleTime;
+ else
+ time1 = middleTime;
+ }
+ else
+ {
+ if (findingAOS)
+ time1 = middleTime;
+ else
+ time2 = middleTime;
+ }
+ if ((time2 - time1).TotalSeconds() < 1.0)
+ {
+ running = false;
+ int us = middleTime.Microsecond();
+ middleTime = middleTime.AddMicroseconds(-us);
+ middleTime = middleTime.AddSeconds(findingAOS ? 1 : -1);
+ }
+ }
+ running = true;
+ cnt = 0;
+ while (running && (cnt++ < 6))
+ {
+ Eci eci = sgp4.FindPosition(middleTime);
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+ if (topo.elevation > minElevation)
+ middleTime = middleTime.AddSeconds(findingAOS ? -1 : 1);
+ else
+ running = false;
+ }
+ return middleTime;
+}
+
+// Find when AOS occured, by stepping backwards
+static DateTime findAOSBackwards(Observer& obs, SGP4& sgp4, DateTime& startTime,
+ int predictionPeriod, double minElevation, bool& aosUnknown)
+{
+ DateTime previousTime(startTime);
+ DateTime currentTime(startTime);
+ DateTime endTime(startTime.AddDays(-predictionPeriod));
+
+ while (currentTime >= endTime)
+ {
+ Eci eci = sgp4.FindPosition(currentTime);
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+ if (topo.elevation < minElevation)
+ {
+ aosUnknown = false;
+ return findCrossingPoint(obs, sgp4, currentTime, previousTime, minElevation, true);
+ }
+ previousTime = currentTime;
+ currentTime = currentTime - TimeSpan(0, 0, 180);
+ }
+ aosUnknown = true;
+ return currentTime;
+}
+
+bool inPassWindow(DateTime dateTime, QTime passStartTime, QTime passEndTime, bool utc)
+{
+ // Don't compare seconds as not currently settable in GUI
+ QDateTime qdt = dateTimeToQDateTime(dateTime);
+ if (!utc)
+ qdt = qdt.toLocalTime();
+ QTime qt(qdt.time().hour(), qdt.time().minute());
+ passStartTime = QTime(passStartTime.hour(), passStartTime.minute());
+ passEndTime = QTime(passEndTime.hour(), passEndTime.minute());
+ // If passEndTime is before passStartTime, then we allow overnight passes
+ if (passEndTime > passStartTime)
+ {
+ return (qt >= passStartTime) && (qt <= passEndTime);
+ }
+ else
+ {
+ return (qt <= passEndTime) || (qt >= passStartTime);
+ }
+}
+
+// Create a list of satellite passes, between the given start and end times, that exceed the specified minimum elevation
+// We return an uninitalised QDateTime if AOS or LOS is outside of predictionPeriod
+static QList createPassList(Observer& obs, SGP4& sgp4, DateTime& startTime,
+ int predictionPeriod, double minAOSElevation, double minPassElevationDeg,
+ QTime passStartTime, QTime passEndTime, bool utc,
+ int noOfPasses)
+{
+ QList passes;
+ bool aos = false;
+ bool aosUnknown = true;
+ double aosAz;
+ double losAz;
+ DateTime previousTime(startTime);
+ DateTime currentTime(startTime);
+ DateTime endTime(startTime.AddDays(predictionPeriod));
+ DateTime aosTime;
+ DateTime losTime;
+
+ while (currentTime < endTime)
+ {
+ bool endOfPass = false;
+ Eci eci = sgp4.FindPosition(currentTime);
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+
+ if (!aos && (topo.elevation > minAOSElevation))
+ {
+ if (startTime == currentTime)
+ {
+ // AOS is before startTime
+ aosTime = findAOSBackwards(obs, sgp4, startTime, predictionPeriod, minAOSElevation, aosUnknown);
+ }
+ else
+ {
+ aosTime = findCrossingPoint(obs, sgp4, previousTime, currentTime, minAOSElevation, true);
+ aosUnknown = false;
+ }
+ aos = true;
+ eci = sgp4.FindPosition(aosTime);
+ topo = obs.GetLookAngle(eci);
+ aosAz = Units::radiansToDegrees(topo.azimuth);
+ }
+ else if (aos && (topo.elevation < minAOSElevation))
+ {
+ aos = false;
+ endOfPass = true;
+ losTime = findCrossingPoint(obs, sgp4, previousTime, currentTime, minAOSElevation, false);
+ eci = sgp4.FindPosition(losTime);
+ topo = obs.GetLookAngle(eci);
+ losAz = Units::radiansToDegrees(topo.azimuth);
+ double maxElevationDeg = findMaxElevation(obs, sgp4, aosTime, losTime);
+ if ((maxElevationDeg >= minPassElevationDeg)
+ && inPassWindow(aosTime, passStartTime, passEndTime, utc)
+ && inPassWindow(losTime, passStartTime, passEndTime, utc))
+ {
+ SatellitePass *pass = new SatellitePass;
+ pass->m_aos = aosUnknown ? QDateTime() : dateTimeToQDateTime(aosTime);
+ pass->m_los = dateTimeToQDateTime(losTime);
+ pass->m_maxElevation = maxElevationDeg;
+ pass->m_aosAzimuth = aosAz;
+ pass->m_losAzimuth = losAz;
+ pass->m_northToSouth = std::min(360.0-aosAz, aosAz-0.0) < std::min(360.0-losAz, losAz-0.0);
+ passes.append(pass);
+ noOfPasses--;
+ if (noOfPasses <= 0)
+ return passes;
+ }
+ }
+ previousTime = currentTime;
+ if (endOfPass)
+ currentTime = currentTime + TimeSpan(0, 30, 0); // 30 minutes - no orbit likely to be that fast
+ else
+ currentTime = currentTime + TimeSpan(0, 0, 180);
+ if (currentTime > endTime)
+ currentTime = endTime;
+ }
+ if (aos)
+ {
+ // Pass still in progress at end time
+ Eci eci = sgp4.FindPosition(currentTime);
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+ losAz = Units::radiansToDegrees(topo.azimuth);
+ double maxElevationDeg = findMaxElevation(obs, sgp4, aosTime, losTime);
+ if ((maxElevationDeg >= minPassElevationDeg)
+ && inPassWindow(aosTime, passStartTime, passEndTime, utc)
+ && inPassWindow(losTime, passStartTime, passEndTime, utc))
+ {
+ SatellitePass *pass = new SatellitePass;
+ pass->m_aos = aosUnknown ? QDateTime() : dateTimeToQDateTime(aosTime);
+ pass->m_los = QDateTime();
+ pass->m_aosAzimuth = aosAz;
+ pass->m_losAzimuth = losAz;
+ pass->m_maxElevation = maxElevationDeg;
+ pass->m_northToSouth = std::min(360.0-aosAz, aosAz-0.0) < std::min(360.0-losAz, losAz-0.0);
+ passes.append(pass);
+ }
+ }
+
+ return passes;
+}
+
+void getSatelliteState(QDateTime dateTime,
+ const QString& tle0, const QString& tle1, const QString& tle2,
+ double latitude, double longitude, double altitude,
+ int predictionPeriod, int minAOSElevationDeg, int minPassElevationDeg,
+ QTime passStartTime, QTime passFinishTime, bool utc,
+ int noOfPasses, int groundTrackSteps, SatelliteState *satState)
+{
+ try {
+ Tle tle = Tle(tle0.toStdString(), tle1.toStdString(), tle2.toStdString());
+ SGP4 sgp4(tle);
+ Observer obs(latitude, longitude, altitude);
+
+ DateTime dt = qDateTimeToDateTime(dateTime);
+
+ // Calculate satellite position
+ Eci eci = sgp4.FindPosition(dt);
+
+ // Calculate angle to satellite from antenna
+ CoordTopocentric topo = obs.GetLookAngle(eci);
+
+ // Convert satellite position to geodetic coordinates (lat and long)
+ CoordGeodetic geo = eci.ToGeodetic();
+
+ satState->m_latitude = Units::radiansToDegrees(geo.latitude);
+ satState->m_longitude = Units::radiansToDegrees(geo.longitude);
+ satState->m_altitude = geo.altitude;
+ satState->m_azimuth = Units::radiansToDegrees(topo.azimuth);
+ satState->m_elevation = Units::radiansToDegrees(topo.elevation);
+ satState->m_range = topo.range;
+ satState->m_rangeRate = topo.range_rate;
+ OrbitalElements ele(tle);
+ satState->m_speed = eci.Velocity().Magnitude();
+ satState->m_period = ele.Period();
+ if (noOfPasses > 0)
+ {
+ qDeleteAll(satState->m_passes);
+ satState->m_passes = createPassList(obs, sgp4, dt, predictionPeriod,
+ Units::degreesToRadians((double)minAOSElevationDeg),
+ minPassElevationDeg,
+ passStartTime, passFinishTime, utc,
+ noOfPasses);
+ }
+
+ getGroundTrack(dateTime, tle0, tle1, tle2, groundTrackSteps, false, satState->m_groundTrack);
+ getGroundTrack(dateTime, tle0, tle1, tle2, groundTrackSteps, true, satState->m_predictedGroundTrack);
+ }
+ catch (SatelliteException& se)
+ {
+ qDebug() << "getSatelliteState: " << satState->m_name << ": " << se.what();
+ }
+ catch (DecayedException& de)
+ {
+ qDebug() << "getSatelliteState: " << satState->m_name << ": " << de.what();
+ }
+ catch (TleException& tlee)
+ {
+ qDebug() << "getSatelliteState: " << satState->m_name << ": " << tlee.what();
+ }
+}
diff --git a/plugins/feature/satellitetracker/satellitetrackersgp4.h b/plugins/feature/satellitetracker/satellitetrackersgp4.h
new file mode 100644
index 000000000..edd8eb090
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackersgp4.h
@@ -0,0 +1,73 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITETRACKERSGP4_H_
+#define INCLUDE_FEATURE_SATELLITETRACKERSGP4_H_
+
+#include
+#include
+#include
+#include
+
+using namespace QtCharts;
+
+struct SatellitePass {
+ QDateTime m_aos;
+ QDateTime m_los;
+ double m_maxElevation; // Degrees
+ double m_aosAzimuth; // Degrees
+ double m_losAzimuth; // Degrees
+ bool m_northToSouth;
+};
+
+struct SatelliteState {
+ QString m_name;
+ double m_latitude; // Degrees
+ double m_longitude; // Degrees
+ double m_altitude; // km
+ double m_azimuth; // Degrees
+ double m_elevation; // Degrees
+ double m_range; // km
+ double m_rangeRate; // km/s
+ double m_speed;
+ double m_period;
+ QList m_passes;
+ QList m_groundTrack;
+ QList m_predictedGroundTrack;
+};
+
+void getGroundTrack(QDateTime dateTime,
+ const QString& tle0, const QString& tle1, const QString& tle2,
+ int steps, QList& coordinates);
+
+void getSatelliteState(QDateTime dateTime,
+ const QString& tle0, const QString& tle1, const QString& tle2,
+ double latitude, double longitude, double altitude,
+ int predictionPeriod, int minAOSElevationDeg, int minPassElevationDeg,
+ QTime passStartTime, QTime passFinishTime, bool utc,
+ int noOfPasses, int groundTrackSteps, SatelliteState *satState);
+
+void getPassAzEl(QLineSeries *azimuth, QLineSeries *elevation, QLineSeries *polar,
+ const QString& tle0, const QString& tle1, const QString& tle2,
+ double latitude, double longitude, double altitude,
+ QDateTime& aos, QDateTime& los);
+
+bool getPassesThrough0Deg(const QString& tle0, const QString& tle1, const QString& tle2,
+ double latitude, double longitude, double altitude,
+ QDateTime& aos, QDateTime& los);
+
+#endif // INCLUDE_FEATURE_SATELLITETRACKERSGP4_H_
diff --git a/plugins/feature/satellitetracker/satellitetrackerwebapiadapter.cpp b/plugins/feature/satellitetracker/satellitetrackerwebapiadapter.cpp
new file mode 100644
index 000000000..37ec7602e
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackerwebapiadapter.cpp
@@ -0,0 +1,52 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "SWGFeatureSettings.h"
+#include "satellitetracker.h"
+#include "satellitetrackerwebapiadapter.h"
+
+SatelliteTrackerWebAPIAdapter::SatelliteTrackerWebAPIAdapter()
+{}
+
+SatelliteTrackerWebAPIAdapter::~SatelliteTrackerWebAPIAdapter()
+{}
+
+int SatelliteTrackerWebAPIAdapter::webapiSettingsGet(
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage)
+{
+ (void) errorMessage;
+ response.setSatelliteTrackerSettings(new SWGSDRangel::SWGSatelliteTrackerSettings());
+ response.getSatelliteTrackerSettings()->init();
+ SatelliteTracker::webapiFormatFeatureSettings(response, m_settings);
+
+ return 200;
+}
+
+int SatelliteTrackerWebAPIAdapter::webapiSettingsPutPatch(
+ bool force,
+ const QStringList& featureSettingsKeys,
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage)
+{
+ (void) force; // no action
+ (void) errorMessage;
+ SatelliteTracker::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response);
+
+ return 200;
+}
diff --git a/plugins/feature/satellitetracker/satellitetrackerwebapiadapter.h b/plugins/feature/satellitetracker/satellitetrackerwebapiadapter.h
new file mode 100644
index 000000000..d287e995f
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackerwebapiadapter.h
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB. //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_SATELLITETRACKER_WEBAPIADAPTER_H
+#define INCLUDE_SATELLITETRACKER_WEBAPIADAPTER_H
+
+#include "feature/featurewebapiadapter.h"
+#include "satellitetrackersettings.h"
+
+/**
+ * Standalone API adapter only for the settings
+ */
+class SatelliteTrackerWebAPIAdapter : public FeatureWebAPIAdapter {
+public:
+ SatelliteTrackerWebAPIAdapter();
+ virtual ~SatelliteTrackerWebAPIAdapter();
+
+ virtual QByteArray serialize() const { return m_settings.serialize(); }
+ virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
+
+ virtual int webapiSettingsGet(
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage);
+
+ virtual int webapiSettingsPutPatch(
+ bool force,
+ const QStringList& featureSettingsKeys,
+ SWGSDRangel::SWGFeatureSettings& response,
+ QString& errorMessage);
+
+private:
+ SatelliteTrackerSettings m_settings;
+};
+
+#endif // INCLUDE_SATELLITETRACKER_WEBAPIADAPTER_H
diff --git a/plugins/feature/satellitetracker/satellitetrackerworker.cpp b/plugins/feature/satellitetracker/satellitetrackerworker.cpp
new file mode 100644
index 000000000..7bfaf56e5
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackerworker.cpp
@@ -0,0 +1,826 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "SWGTargetAzimuthElevation.h"
+#include "SWGMapItem.h"
+
+#include "webapi/webapiadapterinterface.h"
+#include "webapi/webapiutils.h"
+
+#include "util/units.h"
+#include "device/deviceset.h"
+#include "device/deviceapi.h"
+#include "channel/channelwebapiutils.h"
+#include "maincore.h"
+
+#include "satellitetracker.h"
+#include "satellitetrackerworker.h"
+#include "satellitetrackerreport.h"
+#include "satellitetrackersgp4.h"
+
+MESSAGE_CLASS_DEFINITION(SatelliteTrackerWorker::MsgConfigureSatelliteTrackerWorker, Message)
+MESSAGE_CLASS_DEFINITION(SatelliteTrackerReport::MsgReportSat, Message)
+MESSAGE_CLASS_DEFINITION(SatelliteTrackerReport::MsgReportAOS, Message)
+MESSAGE_CLASS_DEFINITION(SatelliteTrackerReport::MsgReportLOS, Message)
+MESSAGE_CLASS_DEFINITION(SatelliteTrackerReport::MsgReportTarget, Message)
+
+SatelliteTrackerWorker::SatelliteTrackerWorker(SatelliteTracker* satelliteTracker, WebAPIAdapterInterface *webAPIAdapterInterface) :
+ m_satelliteTracker(satelliteTracker),
+ m_webAPIAdapterInterface(webAPIAdapterInterface),
+ m_msgQueueToFeature(nullptr),
+ m_msgQueueToGUI(nullptr),
+ m_running(false),
+ m_mutex(QMutex::Recursive),
+ m_recalculatePasses(true),
+ m_flipRotation(false),
+ m_extendedAzRotation(false)
+{
+ connect(&m_pollTimer, SIGNAL(timeout()), this, SLOT(update()));
+}
+
+SatelliteTrackerWorker::~SatelliteTrackerWorker()
+{
+ m_inputMessageQueue.clear();
+}
+
+void SatelliteTrackerWorker::reset()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ m_inputMessageQueue.clear();
+}
+
+bool SatelliteTrackerWorker::startWork()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
+ m_pollTimer.start((int)round(m_settings.m_updatePeriod*1000.0));
+ // Resume doppler timers
+ QHashIterator itr(m_workerState);
+ while (itr.hasNext())
+ {
+ itr.next();
+ SatWorkerState *satWorkerState = itr.value();
+ if (satWorkerState->m_dopplerTimer.interval() > 0)
+ satWorkerState->m_dopplerTimer.start();
+ }
+ m_recalculatePasses = true;
+ m_running = true;
+ return m_running;
+}
+
+void SatelliteTrackerWorker::stopWork()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
+ m_pollTimer.stop();
+ // Stop doppler timers
+ QHashIterator itr(m_workerState);
+ while (itr.hasNext())
+ {
+ itr.next();
+ itr.value()->m_dopplerTimer.stop();
+ }
+ m_running = false;
+}
+
+void SatelliteTrackerWorker::handleInputMessages()
+{
+ Message* message;
+
+ while ((message = m_inputMessageQueue.pop()) != nullptr)
+ {
+ if (handleMessage(*message)) {
+ delete message;
+ }
+ }
+}
+
+bool SatelliteTrackerWorker::handleMessage(const Message& message)
+{
+ if (MsgConfigureSatelliteTrackerWorker::match(message))
+ {
+ QMutexLocker mutexLocker(&m_mutex);
+ MsgConfigureSatelliteTrackerWorker& cfg = (MsgConfigureSatelliteTrackerWorker&) message;
+
+ applySettings(cfg.getSettings(), cfg.getForce());
+ return true;
+ }
+ else if (SatelliteTracker::MsgSatData::match(message))
+ {
+ SatelliteTracker::MsgSatData& satData = (SatelliteTracker::MsgSatData&) message;
+ m_satellites = satData.getSatellites();
+ m_recalculatePasses = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void SatelliteTrackerWorker::applySettings(const SatelliteTrackerSettings& settings, bool force)
+{
+ qDebug() << "SatelliteTrackerWorker::applySettings:"
+ << " m_target: " << settings.m_target
+ << " m_satellites: " << settings.m_satellites
+ << " m_dateTime: " << settings.m_dateTime
+ << " m_utc: " << settings.m_utc
+ << " m_updatePeriod: " << settings.m_updatePeriod
+ << " force: " << force;
+
+ if ((m_settings.m_target != settings.m_target)
+ || (m_settings.m_latitude != settings.m_latitude)
+ || (m_settings.m_longitude != settings.m_longitude)
+ || (m_settings.m_heightAboveSeaLevel != settings.m_heightAboveSeaLevel)
+ || (m_settings.m_dateTime != settings.m_dateTime)
+ || (m_settings.m_utc != settings.m_utc)
+ || (m_settings.m_groundTrackPoints != settings.m_groundTrackPoints)
+ || (m_settings.m_minAOSElevation != settings.m_minAOSElevation)
+ || (m_settings.m_minPassElevation != settings.m_minPassElevation)
+ || (m_settings.m_predictionPeriod != settings.m_predictionPeriod)
+ || (m_settings.m_passStartTime != settings.m_passStartTime)
+ || (m_settings.m_passFinishTime != settings.m_passFinishTime)
+ || (!m_settings.m_drawOnMap && settings.m_drawOnMap)
+ || force)
+ {
+ // Recalculate immediately
+ m_recalculatePasses = true;
+ QTimer::singleShot(1, this, &SatelliteTrackerWorker::update);
+ m_pollTimer.start((int)round(settings.m_updatePeriod*1000.0));
+ }
+ else if ((m_settings.m_updatePeriod != settings.m_updatePeriod) || force)
+ {
+ m_pollTimer.start((int)round(settings.m_updatePeriod*1000.0));
+ }
+
+ if (!settings.m_drawOnMap && m_settings.m_drawOnMap)
+ {
+ QHashIterator itr(m_workerState);
+ while (itr.hasNext())
+ {
+ itr.next();
+ removeFromMap(itr.key());
+ }
+ }
+
+ // Remove satellites no longer needed
+ QMutableHashIterator itr(m_workerState);
+ while (itr.hasNext())
+ {
+ itr.next();
+ if (settings.m_satellites.indexOf(itr.key()) == -1)
+ itr.remove();
+ }
+
+ // Add new satellites
+ for (int i = 0; i < settings.m_satellites.size(); i++)
+ {
+ if (!m_workerState.contains(settings.m_satellites[i]))
+ {
+ SatWorkerState *satWorkerState = new SatWorkerState(settings.m_satellites[i]);
+ m_workerState.insert(settings.m_satellites[i], satWorkerState);
+ connect(&satWorkerState->m_aosTimer, &QTimer::timeout, [this, satWorkerState]() {
+ aos(satWorkerState);
+ });
+ connect(&satWorkerState->m_losTimer, &QTimer::timeout, [this, satWorkerState]() {
+ los(satWorkerState);
+ });
+ m_recalculatePasses = true;
+ }
+ }
+
+ m_settings = settings;
+}
+
+void SatelliteTrackerWorker::removeFromMap(QString id)
+{
+ MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
+ QList *mapMessageQueues = messagePipes.getMessageQueues(m_satelliteTracker, "mapitems");
+ if (mapMessageQueues)
+ sendToMap(mapMessageQueues, id, "", "", 0.0, 0.0, 0.0, 0.0, nullptr, nullptr);
+}
+
+void SatelliteTrackerWorker::sendToMap(QList *mapMessageQueues,
+ QString name, QString image, QString text,
+ double lat, double lon, double altitude, double rotation,
+ QList *track, QList *predictedTrack)
+{
+ QList::iterator it = mapMessageQueues->begin();
+
+ for (; it != mapMessageQueues->end(); ++it)
+ {
+ SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem();
+ swgMapItem->setName(new QString(name));
+ swgMapItem->setLatitude(lat);
+ swgMapItem->setLongitude(lon);
+ swgMapItem->setAltitude(altitude);
+ swgMapItem->setImage(new QString(image));
+ swgMapItem->setImageRotation(rotation);
+ swgMapItem->setText(new QString(text));
+ swgMapItem->setImageMinZoom(0);
+ if (track != nullptr)
+ {
+ QList *mapTrack = new QList();
+ for (int i = 0; i < track->size(); i++)
+ {
+ SWGSDRangel::SWGMapCoordinate* p = new SWGSDRangel::SWGMapCoordinate();
+ QGeoCoordinate *c = track->at(i);
+ p->setLatitude(c->latitude());
+ p->setLongitude(c->longitude());
+ p->setAltitude(c->altitude());
+ mapTrack->append(p);
+ }
+ swgMapItem->setTrack(mapTrack);
+ }
+ if (predictedTrack != nullptr)
+ {
+ QList *mapTrack = new QList();
+ for (int i = 0; i < predictedTrack->size(); i++)
+ {
+ SWGSDRangel::SWGMapCoordinate* p = new SWGSDRangel::SWGMapCoordinate();
+ QGeoCoordinate *c = predictedTrack->at(i);
+ p->setLatitude(c->latitude());
+ p->setLongitude(c->longitude());
+ p->setAltitude(c->altitude());
+ mapTrack->append(p);
+ }
+ swgMapItem->setPredictedTrack(mapTrack);
+ }
+
+ MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_satelliteTracker, swgMapItem);
+ (*it)->push(msg);
+ }
+}
+
+void SatelliteTrackerWorker::update()
+{
+ // Get date and time to calculate position at
+ QDateTime qdt;
+ if (m_settings.m_dateTime == "")
+ qdt = QDateTime::currentDateTimeUtc();
+ else if (m_settings.m_utc)
+ qdt = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
+ else
+ qdt = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs).toUTC();
+
+ QHashIterator itr(m_workerState);
+ while (itr.hasNext())
+ {
+ itr.next();
+ SatWorkerState *satWorkerState = itr.value();
+ QString name = satWorkerState->m_name;
+ if (m_satellites.contains(name))
+ {
+ SatNogsSatellite *sat = m_satellites.value(name);
+ if (sat->m_tle != nullptr)
+ {
+ // Calculate position, AOS/LOS and other details for satellite
+ int noOfPasses;
+ bool recalcAsPastLOS = (satWorkerState->m_satState.m_passes.size() > 0) && (satWorkerState->m_satState.m_passes[0]->m_los < qdt);
+ if (m_recalculatePasses || recalcAsPastLOS)
+ noOfPasses = (name == m_settings.m_target) ? 99 : 1;
+ else
+ noOfPasses = 0;
+ getSatelliteState(qdt, sat->m_tle->m_tle0, sat->m_tle->m_tle1, sat->m_tle->m_tle2,
+ m_settings.m_latitude, m_settings.m_longitude, m_settings.m_heightAboveSeaLevel/1000.0,
+ m_settings.m_predictionPeriod, m_settings.m_minAOSElevation, m_settings.m_minPassElevation,
+ m_settings.m_passStartTime, m_settings.m_passFinishTime, m_settings.m_utc,
+ noOfPasses, m_settings.m_groundTrackPoints, &satWorkerState->m_satState);
+
+ // Update AOS/LOS (only set timers if using real time)
+ if ((m_settings.m_dateTime == "") && (satWorkerState->m_satState.m_passes.size() > 0))
+ {
+ /*int min = 8;
+ QDateTime p1a = QDateTime(QDateTime::currentDateTime().date(), QTime(16, min, 0));
+ QDateTime p1s = QDateTime(QDateTime::currentDateTime().date(), QTime(16, min, 30));
+
+ QDateTime p2a = QDateTime(QDateTime::currentDateTime().date(), QTime(16, min+1, 0));
+ QDateTime p2s = QDateTime(QDateTime::currentDateTime().date(), QTime(16, min+1, 30));
+
+ if (qdt > p1a)
+ {
+ satWorkerState->m_satState.m_passes[0]->m_aos = p2a;
+ satWorkerState->m_satState.m_passes[0]->m_los = p2s;
+ }
+ else
+ {
+ satWorkerState->m_satState.m_passes[0]->m_aos = p1a;
+ satWorkerState->m_satState.m_passes[0]->m_los = p1s;
+ } */
+
+
+ /* if (name == "NOAA 18")
+ {
+ satWorkerState->m_satState.m_passes[0]->m_aos = QDateTime(QDateTime::currentDateTime().date(), QTime(11, 10, 0));
+ satWorkerState->m_satState.m_passes[0]->m_los = QDateTime(QDateTime::currentDateTime().date(), QTime(11, 10, 30));
+ } */
+
+
+ /*if (name == "ISS")
+ {
+ if (m_settings.m_minAOSElevation == 5)
+ {
+ qDebug() << "*********** seting first AOS";
+ satWorkerState->m_satState.m_passes[0]->m_aos = QDateTime(QDateTime::currentDateTime().date(), QTime(14, 10, 0));
+ satWorkerState->m_satState.m_passes[0]->m_los = QDateTime(QDateTime::currentDateTime().date(), QTime(14, 10, 30));
+ }
+ else
+ {
+ qDebug() << "*********** seting second AOS";
+ satWorkerState->m_satState.m_passes[0]->m_aos = QDateTime(QDateTime::currentDateTime().date(), QTime(14, 11, 0));
+ satWorkerState->m_satState.m_passes[0]->m_los = QDateTime(QDateTime::currentDateTime().date(), QTime(14, 11, 30));
+ }
+ }*/
+
+
+ // Do we have a new AOS?
+ if ((satWorkerState->m_aos != satWorkerState->m_satState.m_passes[0]->m_aos) || (satWorkerState->m_los != satWorkerState->m_satState.m_passes[0]->m_los))
+ {
+ qDebug() << "New AOS: " << name << " new: " << satWorkerState->m_satState.m_passes[0]->m_aos << " old: " << satWorkerState->m_aos;
+ qDebug() << "New LOS: " << name << " new: " << satWorkerState->m_satState.m_passes[0]->m_los << " old: " << satWorkerState->m_los;
+ satWorkerState->m_aos = satWorkerState->m_satState.m_passes[0]->m_aos;
+ satWorkerState->m_los = satWorkerState->m_satState.m_passes[0]->m_los;
+ if (satWorkerState->m_aos.isValid())
+ {
+ if (satWorkerState->m_aos > qdt)
+ {
+ satWorkerState->m_aosTimer.setInterval(satWorkerState->m_aos.toMSecsSinceEpoch() - qdt.toMSecsSinceEpoch());
+ satWorkerState->m_aosTimer.setSingleShot(true);
+ satWorkerState->m_aosTimer.start();
+ }
+ else if (qdt < satWorkerState->m_los)
+ aos(satWorkerState);
+
+ if (satWorkerState->m_los.isValid() && (m_settings.m_target == satWorkerState->m_name))
+ calculateRotation(satWorkerState);
+ }
+ if (satWorkerState->m_los.isValid() && (satWorkerState->m_los > qdt))
+ {
+ if (satWorkerState->m_losTimer.isActive() && (satWorkerState->m_losTimer.remainingTime() == 0))
+ {
+ qDebug() << "****** m_losTimer.remainingTime: " << satWorkerState->m_losTimer.remainingTime();
+ qDebug() << "****** m_losTimer.active: " << satWorkerState->m_losTimer.isActive();
+ // LOS hasn't been called yet - do so, before we reset timer
+ los(satWorkerState);
+ }
+ satWorkerState->m_losTimer.setInterval(satWorkerState->m_los.toMSecsSinceEpoch() - qdt.toMSecsSinceEpoch());
+ satWorkerState->m_losTimer.setSingleShot(true);
+ satWorkerState->m_losTimer.start();
+ }
+ }
+ }
+ else
+ {
+ satWorkerState->m_aos = QDateTime();
+ satWorkerState->m_los = QDateTime();
+ satWorkerState->m_aosTimer.stop();
+ satWorkerState->m_losTimer.stop();
+ }
+
+ // Send Az/El of target to Rotator Controllers, if elevation above horizon
+ if ((name == m_settings.m_target) && (satWorkerState->m_satState.m_elevation >= 0))
+ {
+ double azimuth = satWorkerState->m_satState.m_azimuth;
+ double elevation = satWorkerState->m_satState.m_elevation;
+ if (m_extendedAzRotation)
+ {
+ if (azimuth < 180.0)
+ azimuth += 360.0;
+ }
+ else if (m_flipRotation)
+ {
+ azimuth = std::fmod(azimuth + 180.0, 360.0);
+ elevation = 180.0 - elevation;
+ }
+ MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
+ QList *rotatorMessageQueues = messagePipes.getMessageQueues(m_satelliteTracker, "target");
+ if (rotatorMessageQueues)
+ {
+ QList::iterator it = rotatorMessageQueues->begin();
+
+ for (; it != rotatorMessageQueues->end(); ++it)
+ {
+ SWGSDRangel::SWGTargetAzimuthElevation *swgTarget = new SWGSDRangel::SWGTargetAzimuthElevation();
+ swgTarget->setName(new QString(m_settings.m_target));
+ swgTarget->setAzimuth(azimuth);
+ swgTarget->setElevation(elevation);
+ (*it)->push(MainCore::MsgTargetAzimuthElevation::create(m_satelliteTracker, swgTarget));
+ }
+ }
+ }
+
+ // Send to Map
+ if (m_settings.m_drawOnMap)
+ {
+ MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
+ QList *mapMessageQueues = messagePipes.getMessageQueues(m_satelliteTracker, "mapitems");
+ if (mapMessageQueues)
+ {
+ QString image;
+ if (sat->m_name == "ISS")
+ image = "qrc:///satellitetracker/satellitetracker/iss-32.png";
+ else
+ image = "qrc:///satellitetracker/satellitetracker/satellite-32.png";
+
+ QString text = QString("Name: %1\nAltitude: %2 km\nRange: %3 km\nRange rate: %4 km/s\nSpeed: %5 km/h\nPeriod: %6 mins")
+ .arg(sat->m_name)
+ .arg((int)round(satWorkerState->m_satState.m_altitude))
+ .arg((int)round(satWorkerState->m_satState.m_range))
+ .arg(satWorkerState->m_satState.m_rangeRate, 0, 'f', 1)
+ .arg(Units::kmpsToIntegerKPH(satWorkerState->m_satState.m_speed))
+ .arg((int)round(satWorkerState->m_satState.m_period));
+ if (satWorkerState->m_satState.m_passes.size() > 0)
+ {
+ if ((qdt >= satWorkerState->m_satState.m_passes[0]->m_aos) && (qdt <= satWorkerState->m_satState.m_passes[0]->m_los))
+ text = text.append("\nSatellite is visible");
+ else
+ text = text.append("\nAOS in: %1 mins").arg((int)round((satWorkerState->m_satState.m_passes[0]->m_aos.toSecsSinceEpoch() - qdt.toSecsSinceEpoch())/60.0));
+ text = QString("%1\nAOS: %2\nLOS: %3\nMax El: %4%5")
+ .arg(text)
+ .arg(satWorkerState->m_satState.m_passes[0]->m_aos.toString(m_settings.m_dateFormat + " hh:mm"))
+ .arg(satWorkerState->m_satState.m_passes[0]->m_los.toString(m_settings.m_dateFormat + " hh:mm"))
+ .arg((int)round(satWorkerState->m_satState.m_passes[0]->m_maxElevation))
+ .arg(QChar(0xb0));
+ }
+
+ sendToMap(mapMessageQueues, sat->m_name, image, text,
+ satWorkerState->m_satState.m_latitude, satWorkerState->m_satState.m_longitude,
+ satWorkerState->m_satState.m_altitude * 1000.0, 0,
+ &satWorkerState->m_satState.m_groundTrack, &satWorkerState->m_satState.m_predictedGroundTrack);
+ }
+ }
+
+ // Send to GUI
+ if (getMessageQueueToGUI())
+ getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportSat::create(new SatelliteState(satWorkerState->m_satState)));
+ }
+ else
+ qDebug() << "SatelliteTrackerWorker::update: No TLE for " << sat->m_name << ". Can't compute position.";
+ }
+ }
+ m_recalculatePasses = false;
+}
+
+void SatelliteTrackerWorker::aos(SatWorkerState *satWorkerState)
+{
+ qDebug() << "SatelliteTrackerWorker::aos " << satWorkerState->m_name;
+
+ // Indicate AOS to GUI
+ if (getMessageQueueToGUI())
+ {
+ int durationMins = (int)round((satWorkerState->m_los.toSecsSinceEpoch() - satWorkerState->m_aos.toSecsSinceEpoch())/60.0);
+ int maxElevation = 0;
+ if (satWorkerState->m_satState.m_passes.size() > 0)
+ maxElevation = satWorkerState->m_satState.m_passes[0]->m_maxElevation;
+ getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportAOS::create(satWorkerState->m_name, durationMins, maxElevation));
+ }
+
+ // Update target
+ if (m_settings.m_autoTarget && (satWorkerState->m_name != m_settings.m_target))
+ {
+ // Only switch if higher priority (earlier in list) or other target not in AOS
+ SatWorkerState *targetSatWorkerState = m_workerState.value(m_settings.m_target);
+ int currentTargetIdx = m_settings.m_satellites.indexOf(m_settings.m_target);
+ int newTargetIdx = m_settings.m_satellites.indexOf(satWorkerState->m_name);
+ if ((newTargetIdx < currentTargetIdx) || !targetSatWorkerState->hasAOS())
+ {
+ // Stop doppler correction for current target
+ if (m_workerState.contains(m_settings.m_target))
+ m_workerState.value(m_settings.m_target)->m_dopplerTimer.stop();
+
+ qDebug() << "SatelliteTrackerWorker::aos - autoTarget setting " << satWorkerState->m_name;
+ m_settings.m_target = satWorkerState->m_name;
+ // Update GUI with new target
+ if (getMessageQueueToGUI())
+ getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportTarget::create(satWorkerState->m_name));
+ }
+ }
+
+ // TODO: Detect if different device sets are used and support multiple sats simultaneously
+ if (m_settings.m_target == satWorkerState->m_name)
+ applyDeviceAOSSettings(satWorkerState->m_name);
+}
+
+// Determine if we need to flip rotator or use extended azimuth to avoid 360/0 discontinuity
+void SatelliteTrackerWorker::calculateRotation(SatWorkerState *satWorkerState)
+{
+ m_flipRotation = false;
+ m_extendedAzRotation = false;
+ if (satWorkerState->m_satState.m_passes.size() > 0)
+ {
+ SatNogsSatellite *sat = m_satellites.value(satWorkerState->m_name);
+ bool passes0 = getPassesThrough0Deg(sat->m_tle->m_tle0, sat->m_tle->m_tle1, sat->m_tle->m_tle2,
+ m_settings.m_latitude, m_settings.m_longitude, m_settings.m_heightAboveSeaLevel/1000.0,
+ satWorkerState->m_satState.m_passes[0]->m_aos, satWorkerState->m_satState.m_passes[0]->m_los);
+ if (passes0)
+ {
+ double aosAz = satWorkerState->m_satState.m_passes[0]->m_aosAzimuth;
+ double losAz = satWorkerState->m_satState.m_passes[0]->m_losAzimuth;
+ double minAz = std::min(aosAz, losAz);
+ if ((m_settings.m_rotatorMaxAzimuth - 360.0) > minAz)
+ m_extendedAzRotation = true;
+ else if (m_settings.m_rotatorMaxElevation == 180.0)
+ m_flipRotation = true;
+ }
+ }
+}
+
+void SatelliteTrackerWorker::applyDeviceAOSSettings(const QString& name)
+{
+ // Execute global program/script
+ if (!m_settings.m_aosCommand.isEmpty())
+ {
+ qDebug() << "SatelliteTrackerWorker::aos: executing command: " << m_settings.m_aosCommand;
+ QProcess::startDetached(m_settings.m_aosCommand);
+ }
+
+ // Update device set
+ if (m_settings.m_deviceSettings.contains(name))
+ {
+ QList *m_deviceSettingsList = m_settings.m_deviceSettings.value(name);
+
+ MainCore *mainCore = MainCore::instance();
+
+ // Load presets
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+ if (!devSettings->m_presetGroup.isEmpty() && !devSettings->m_deviceSet.isEmpty())
+ {
+ const MainSettings& mainSettings = mainCore->getSettings();
+
+ QString presetType = QString(devSettings->m_deviceSet[0]);
+ const Preset* preset = mainSettings.getPreset(devSettings->m_presetGroup, devSettings->m_presetFrequency, devSettings->m_presetDescription, presetType);
+ if (preset != nullptr)
+ {
+ qDebug() << "SatelliteTrackerWorker::aos: Loading preset " << preset->getDescription() << " to " << devSettings->m_deviceSet[0];
+ unsigned int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ std::vector& deviceSets = mainCore->getDeviceSets();
+ if (deviceSetIndex < deviceSets.size())
+ {
+ MainCore::MsgLoadPreset *msg = MainCore::MsgLoadPreset::create(preset, deviceSetIndex);
+ mainCore->getMainMessageQueue()->push(msg);
+ }
+ else
+ qWarning() << "SatelliteTrackerWorker::aos: device set " << devSettings->m_deviceSet << " does not exist";
+ }
+ else
+ qWarning() << "SatelliteTrackerWorker::aos: Unable to get preset: " << devSettings->m_presetGroup << " " << devSettings->m_presetFrequency << " " << devSettings->m_presetDescription;
+ }
+ }
+
+ // Wait a little bit for presets to load before performing other steps
+ QTimer::singleShot(1000, [this, mainCore, name, m_deviceSettingsList]()
+ {
+
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+
+ // Override frequency
+ if (devSettings->m_frequency != 0)
+ {
+ qDebug() << "SatelliteTrackerWorker::aos: setting frequency to: " << devSettings->m_frequency;
+ int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ ChannelWebAPIUtils::setCenterFrequency(deviceSetIndex, devSettings->m_frequency);
+ }
+
+ // Execute per satellite program/script
+ if (!devSettings->m_aosCommand.isEmpty())
+ {
+ qDebug() << "SatelliteTrackerWorker::aos: executing command: " << devSettings->m_aosCommand;
+ QProcess::startDetached(devSettings->m_aosCommand);
+ }
+
+ }
+
+ // Start acquisition - Need to use WebAPI, in order for GUI to correctly reflect being started
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+ if (devSettings->m_startOnAOS)
+ {
+ qDebug() << "SatelliteTrackerWorker::aos: starting acqusition";
+ int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ ChannelWebAPIUtils::run(deviceSetIndex);
+ }
+ }
+
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+
+ // Start file sinks (See issue #782 - currently must occur after starting acqusition)
+ if (devSettings->m_startStopFileSink)
+ {
+ qDebug() << "SatelliteTrackerWorker::aos: starting file sinks";
+ int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ ChannelWebAPIUtils::startStopFileSinks(deviceSetIndex, true);
+ }
+ }
+
+ // Send AOS message to channels
+ SatWorkerState *satWorkerState = m_workerState.value(name);
+ ChannelWebAPIUtils::satelliteAOS(name, satWorkerState->m_satState.m_passes[0]->m_northToSouth);
+
+ // Start Doppler correction, if needed
+ satWorkerState->m_initFrequencyOffset.clear();
+ bool requiresDoppler = false;
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+ if (devSettings->m_doppler.size() > 0)
+ {
+ requiresDoppler = true;
+ for (int j = 0; j < devSettings->m_doppler.size(); j++)
+ {
+ int offset;
+ int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ if (ChannelWebAPIUtils::getFrequencyOffset(deviceSetIndex, devSettings->m_doppler[j], offset))
+ {
+ satWorkerState->m_initFrequencyOffset.append(offset);
+ qDebug() << "SatelliteTrackerWorker::applyDeviceAOSSettings: Initial frequency offset: " << offset;
+ }
+ else
+ {
+ qDebug() << "SatelliteTrackerWorker::applyDeviceAOSSettings: Failed to get initial frequency offset";
+ satWorkerState->m_initFrequencyOffset.append(0);
+ }
+ }
+ }
+ }
+ if (requiresDoppler)
+ {
+ satWorkerState->m_dopplerTimer.setInterval(m_settings.m_dopplerPeriod);
+ satWorkerState->m_dopplerTimer.start();
+ connect(&satWorkerState->m_dopplerTimer, &QTimer::timeout, [this, satWorkerState]() {
+ doppler(satWorkerState);
+ });
+ }
+ });
+ }
+ else
+ {
+ // Send AOS message to channels
+ SatWorkerState *satWorkerState = m_workerState.value(name);
+ ChannelWebAPIUtils::satelliteAOS(name, satWorkerState->m_satState.m_passes[0]->m_northToSouth);
+ }
+
+}
+
+void SatelliteTrackerWorker::doppler(SatWorkerState *satWorkerState)
+{
+ qDebug() << "SatelliteTrackerWorker::doppler " << satWorkerState->m_name;
+
+ QList *m_deviceSettingsList = m_settings.m_deviceSettings.value(satWorkerState->m_name);
+ if (m_deviceSettingsList != nullptr)
+ {
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+ if (devSettings->m_doppler.size() > 0)
+ {
+ // Get center frequency for this device
+ int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ double centerFrequency;
+ if (ChannelWebAPIUtils::getCenterFrequency(deviceSetIndex, centerFrequency))
+ {
+ // Calculate frequency delta due to Doppler
+ double c = 299792458.0;
+ double deltaF = centerFrequency * satWorkerState->m_satState.m_rangeRate * 1000.0 / c;
+
+ for (int j = 0; j < devSettings->m_doppler.size(); j++)
+ {
+ // For receive, we subtract, transmit we add
+ int offset;
+ if (devSettings->m_deviceSet[0] == "R")
+ offset = satWorkerState->m_initFrequencyOffset[i] - (int)round(deltaF);
+ else
+ offset = satWorkerState->m_initFrequencyOffset[i] + (int)round(deltaF);
+
+ if (!ChannelWebAPIUtils::setFrequencyOffset(deviceSetIndex, devSettings->m_doppler[j], offset))
+ qDebug() << "SatelliteTrackerWorker::doppler: Failed to set frequency offset";
+ }
+ }
+ else
+ qDebug() << "SatelliteTrackerWorker::doppler: couldn't get centre frequency for " << devSettings->m_deviceSet;
+ }
+ }
+ }
+}
+
+void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState)
+{
+ qDebug() << "SatelliteTrackerWorker::los " << satWorkerState->m_name;
+
+ // Indicate LOS to GUI
+ if (getMessageQueueToGUI())
+ getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportLOS::create(satWorkerState->m_name));
+
+ // Stop Doppler timer, and set interval to 0, so we don't restart it in start()
+ satWorkerState->m_dopplerTimer.stop();
+ satWorkerState->m_dopplerTimer.setInterval(0);
+
+ if (m_settings.m_target == satWorkerState->m_name)
+ {
+ // Execute program/script
+ if (!m_settings.m_losCommand.isEmpty())
+ {
+ qDebug() << "SatelliteTrackerWorker::los: executing command: " << m_settings.m_losCommand;
+ QProcess::startDetached(m_settings.m_losCommand);
+ }
+
+ if (m_settings.m_deviceSettings.contains(satWorkerState->m_name))
+ {
+ QList *m_deviceSettingsList = m_settings.m_deviceSettings.value(satWorkerState->m_name);
+
+ // Stop file sinks
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+ if (devSettings->m_startStopFileSink)
+ {
+ qDebug() << "SatelliteTrackerWorker::los: stopping file sinks";
+ int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ ChannelWebAPIUtils::startStopFileSinks(deviceSetIndex, false);
+ }
+ }
+
+ // Send LOS message to channels
+ ChannelWebAPIUtils::satelliteLOS(satWorkerState->m_name);
+
+ // Stop acquisition
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+ if (devSettings->m_stopOnLOS)
+ {
+ int deviceSetIndex = devSettings->m_deviceSet.mid(1).toInt();
+ ChannelWebAPIUtils::stop(deviceSetIndex);
+ }
+ }
+
+ // Execute per satellite program/script
+ // Do after stopping acquisition, so files are closed by file sink
+ for (int i = 0; i < m_deviceSettingsList->size(); i++)
+ {
+ SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i);
+ if (!devSettings->m_losCommand.isEmpty())
+ {
+ qDebug() << "SatelliteTrackerWorker::los: executing command: " << devSettings->m_losCommand;
+ QProcess::startDetached(devSettings->m_losCommand);
+ }
+ }
+ }
+ }
+
+ // Is another lower-priority satellite with AOS available to switch to?
+ if (m_settings.m_autoTarget)
+ {
+ for (int i = m_settings.m_satellites.indexOf(m_settings.m_target) + 1; i < m_settings.m_satellites.size(); i++)
+ {
+ if (m_workerState.contains(m_settings.m_satellites[i]))
+ {
+ SatWorkerState *newSatWorkerState = m_workerState.value(m_settings.m_satellites[i]);
+ if (newSatWorkerState->hasAOS())
+ {
+ qDebug() << "SatelliteTrackerWorker::los - autoTarget setting " << m_settings.m_satellites[i];
+ m_settings.m_target = m_settings.m_satellites[i];
+ // Update GUI with new target
+ if (getMessageQueueToGUI())
+ getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportTarget::create(m_settings.m_target));
+ // Apply device settings
+ applyDeviceAOSSettings(m_settings.m_target);
+ break;
+ }
+ }
+ }
+ }
+
+ m_recalculatePasses = true;
+}
diff --git a/plugins/feature/satellitetracker/satellitetrackerworker.h b/plugins/feature/satellitetracker/satellitetrackerworker.h
new file mode 100644
index 000000000..9009359ba
--- /dev/null
+++ b/plugins/feature/satellitetracker/satellitetrackerworker.h
@@ -0,0 +1,144 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// Copyright (C) 2020 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_FEATURE_SATELLITETRACKERWORKER_H_
+#define INCLUDE_FEATURE_SATELLITETRACKERWORKER_H_
+
+#include
+#include
+#include
+
+#include "util/message.h"
+#include "util/messagequeue.h"
+#include "util/astronomy.h"
+
+#include "satellitetrackersettings.h"
+#include "satellitetrackersgp4.h"
+#include "satnogs.h"
+
+class WebAPIAdapterInterface;
+class QTcpServer;
+class QTcpSocket;
+class SatelliteTracker;
+class SatelliteTrackerWorker;
+class QDateTime;
+class QGeoCoordinate;
+
+class SatWorkerState
+{
+public:
+ SatWorkerState(QString name) :
+ m_name(name)
+ {
+ m_satState.m_name = name;
+ }
+
+ bool hasAOS()
+ {
+ QDateTime currentTime = QDateTime::currentDateTime();
+ return (m_aos <= currentTime) && (m_los > currentTime);
+ }
+
+protected:
+ QString m_name; // Name of the satellite
+ QDateTime m_aos; // Time of next AOS
+ QDateTime m_los; // Time of next LOS
+ QTimer m_aosTimer;
+ QTimer m_losTimer;
+ QTimer m_dopplerTimer;
+ QList m_initFrequencyOffset;
+ SatelliteState m_satState;
+
+ friend SatelliteTrackerWorker;
+};
+
+class SatelliteTrackerWorker : public QObject
+{
+ Q_OBJECT
+
+public:
+ class MsgConfigureSatelliteTrackerWorker : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const SatelliteTrackerSettings& getSettings() const { return m_settings; }
+ bool getForce() const { return m_force; }
+
+ static MsgConfigureSatelliteTrackerWorker* create(const SatelliteTrackerSettings& settings, bool force)
+ {
+ return new MsgConfigureSatelliteTrackerWorker(settings, force);
+ }
+
+ private:
+ SatelliteTrackerSettings m_settings;
+ bool m_force;
+
+ MsgConfigureSatelliteTrackerWorker(const SatelliteTrackerSettings& settings, bool force) :
+ Message(),
+ m_settings(settings),
+ m_force(force)
+ { }
+ };
+
+ SatelliteTrackerWorker(SatelliteTracker* satelliteTracker, WebAPIAdapterInterface *webAPIAdapterInterface);
+ ~SatelliteTrackerWorker();
+ void reset();
+ bool startWork();
+ void stopWork();
+ bool isRunning() const { return m_running; }
+ MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+ void setMessageQueueToFeature(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; }
+ void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; }
+
+private:
+
+ SatelliteTracker* m_satelliteTracker;
+ WebAPIAdapterInterface *m_webAPIAdapterInterface;
+ MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
+ MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
+ MessageQueue *m_msgQueueToGUI;
+ SatelliteTrackerSettings m_settings;
+ bool m_running;
+ QMutex m_mutex;
+ QTimer m_pollTimer;
+ QHash m_satellites;
+ QHash m_workerState;
+ bool m_recalculatePasses; //!< Recalculate passes as something has changed
+ bool m_flipRotation; //!< Use 180 elevation to avoid 360/0 degree discontinutiy
+ bool m_extendedAzRotation; //!< Use 450+ degree azimuth to avoid 360/0 degree discontinuity
+
+ bool handleMessage(const Message& cmd);
+ void applySettings(const SatelliteTrackerSettings& settings, bool force = false);
+ MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; }
+ void removeFromMap(QString id);
+ void sendToMap(QList *mapMessageQueues, QString id, QString image, QString text,
+ double lat, double lon, double altitude, double rotation,
+ QList *track = nullptr, QList *predictedTrack = nullptr);
+ void applyDeviceAOSSettings(const QString& name);
+ void startStopSinks(bool start);
+ void calculateRotation(SatWorkerState *satWorkerState);
+
+private slots:
+ void handleInputMessages();
+ void update();
+ void aos(SatWorkerState *satWorkerState);
+ void los(SatWorkerState *satWorkerState);
+ void doppler(SatWorkerState *satWorkerState);
+};
+
+#endif // INCLUDE_FEATURE_SATELLITETRACKERWORKER_H_
diff --git a/plugins/feature/satellitetracker/satnogs.h b/plugins/feature/satellitetracker/satnogs.h
new file mode 100644
index 000000000..3f5baae04
--- /dev/null
+++ b/plugins/feature/satellitetracker/satnogs.h
@@ -0,0 +1,263 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_SATNOGS_H_
+#define INCLUDE_SATNOGS_H_
+
+#include
+#include
+#include
+#include
+#include
+
+struct SatNogsTransmitter {
+
+ int m_noradCatId; // To link to which satellite this is for
+ QString m_description; // E.g. GMSK9k6 G3RUH AX.25 TLM
+ bool m_alive;
+ QString m_type; // "Transmitter", "Trasceiver" or "Transponder"
+ qint64 m_uplinkLow;
+ qint64 m_uplinkHigh;
+ qint64 m_downlinkLow;
+ qint64 m_downlinkHigh;
+ QString m_mode; // E.g. "GMSK", "CW", "AFSK", "BPSK", "USB", etc
+ int m_baud;
+ QString m_status; // "active", "inactive", "invalid"
+ QString m_service; // "Amateur", "Earth Exploration", "Maritime", "Meteorological", "Mobile", "Space Research"
+
+ SatNogsTransmitter(const QJsonObject& obj)
+ {
+ m_noradCatId = obj["norad_cat_id"].toInt();
+ m_description = obj["description"].toString();
+ m_alive = obj["alive"].toBool();
+ m_type = obj["type"].toString();
+ m_uplinkLow = (qint64)obj["uplink_low"].toDouble();
+ m_uplinkHigh = (qint64)obj["uplink_high"].toDouble();
+ m_downlinkLow = (qint64)obj["downlink_low"].toDouble();
+ m_downlinkHigh = (qint64)obj["downlink_high"].toDouble();
+ m_mode = obj["mode"].toString();
+ m_baud = obj["baud"].toInt();
+ m_status = obj["status"].toString();
+ m_service = obj["service"].toString();
+ }
+
+ static QList createList(QJsonArray array)
+ {
+ QList list;
+ for (int i = 0; i < array.size(); i++)
+ {
+ QJsonValue value = array.at(i);
+ if (value.isObject())
+ list.append(new SatNogsTransmitter(value.toObject()));
+ }
+
+ return list;
+ }
+
+ static QString getFrequencyText(quint64 frequency)
+ {
+ if (frequency > 1000000000)
+ return QString("%1 GHz").arg(frequency/1000000000.0, 0, ',', 6);
+ else if (frequency > 1000000)
+ return QString("%1 MHz").arg(frequency/1000000.0, 0, ',', 3);
+ else
+ return QString("%1 kHz").arg(frequency/1000.0, 0, ',', 3);
+ }
+
+ static QString getFrequencyRangeText(quint64 low, quint64 high)
+ {
+ if (high > 1000000000)
+ return QString("%1-%2 GHz").arg(low/1000000000.0, 0, ',', 6).arg(high/1000000000.0, 0, ',', 6);
+ else if (high > 1000000)
+ return QString("%1-%2 MHz").arg(low/1000000.0, 0, ',', 3).arg(high/1000000.0, 0, ',', 3);
+ else
+ return QString("%1-%2 kHz").arg(low/1000.0, 0, ',', 3).arg(high/1000.0, 0, ',', 3);
+ }
+
+};
+
+struct SatNogsTLE {
+
+ int m_noradCatId; // To link to which satellite this is for
+ QString m_tle0;
+ QString m_tle1;
+ QString m_tle2;
+ QDateTime m_updated;
+
+ SatNogsTLE(const QJsonObject &obj)
+ {
+ m_noradCatId = obj["norad_cat_id"].toInt();
+ m_tle0 = obj["tle0"].toString();
+ m_tle1 = obj["tle1"].toString();
+ m_tle2 = obj["tle2"].toString();
+ m_updated = QDateTime::fromString(obj["updated"].toString(), Qt::ISODateWithMs);
+ }
+
+ SatNogsTLE(const QString& tle0, const QString& tle1, const QString& tle2)
+ {
+ m_noradCatId = tle2.mid(2, 5).toInt();
+ m_tle0 = tle0;
+ m_tle1 = tle1;
+ m_tle2 = tle2;
+ }
+
+ static QList createList(QJsonArray array)
+ {
+ QList list;
+ for (int i = 0; i < array.size(); i++)
+ {
+ QJsonValue value = array.at(i);
+ if (value.isObject())
+ list.append(new SatNogsTLE(value.toObject()));
+ }
+
+ return list;
+ }
+
+ static QList createList(const QByteArray& array)
+ {
+ QList list;
+ QList lines = array.split('\n');
+ for (int i = 0; i < lines.size(); i += 3)
+ {
+ if (i + 3 < lines.size())
+ {
+ QString tle0(lines[i]);
+ QString tle1(lines[i+1]);
+ QString tle2(lines[i+2]);
+ list.append(new SatNogsTLE(tle0.trimmed(), tle1.trimmed(), tle2.trimmed()));
+ }
+ }
+ return list;
+ }
+};
+
+struct SatNogsSatellite {
+
+ int m_noradCatId;
+ QString m_name;
+ QStringList m_names; // Alterantive names - JSON "AO-10\r\nOSCAR-10"
+ QString m_image; // URL to image of satellie - JSON example: "https://db-satnogs.freetls.fastly.net/media/satellites/sigma.jpg"
+ QString m_status; // "alive" "re-entered" "dead" "future" or "" for TLE only sats
+ QDateTime m_decayed; // Date of decay. JSON "2018-05-19T00:00:00Z"
+ QDateTime m_launched;
+ QDateTime m_deployed;
+ QString m_website;
+ QString m_operator; // "None" or "European Space Agency",
+ QString m_countries; // "US" or "ES"
+
+ QList m_transmitters;
+ SatNogsTLE *m_tle;
+
+ SatNogsSatellite(const QJsonObject& obj)
+ {
+ m_noradCatId = obj["norad_cat_id"].toInt();
+ m_name = obj["name"].toString();
+ m_names = obj["names"].toString().split("\r\n");
+ if ((m_names.size() == 1) && m_names[0].isEmpty())
+ m_names = QStringList();
+ m_image = obj["image"].toString();
+ m_status = obj["status"].toString();
+ if (!obj["decayed"].isNull())
+ m_decayed = QDateTime::fromString(obj["decayed"].toString(), Qt::ISODate);
+ if (!obj["launched"].isNull())
+ m_launched = QDateTime::fromString(obj["launched"].toString(), Qt::ISODate);
+ if (!obj["deployed"].isNull())
+ m_deployed = QDateTime::fromString(obj["deployed"].toString(), Qt::ISODate);
+ m_website = obj["website"].toString();
+ m_operator = obj["operator"].toString();
+ m_countries = obj["countries"].toString();
+ m_tle = nullptr;
+ }
+
+ SatNogsSatellite(SatNogsTLE *tle)
+ {
+ // Extract names from TLE
+ // tle0 is of the form:
+ // MOZHAYETS 4 (RS-22)
+ // GOES 9 [-]
+ QRegExp re("([A-Za-z0-9\\- ]+)([\\(]([A-Z0-9\\- ]+)[\\)])?");
+ if (re.indexIn(tle->m_tle0) != -1)
+ {
+ QStringList groups = re.capturedTexts();
+ m_name = groups[1].trimmed();
+ if ((groups.size() >= 4) && (groups[3] != "-") && !groups[3].isEmpty())
+ m_names = QStringList({groups[3].trimmed()});
+ m_noradCatId = tle->m_tle2.mid(2, 5).toInt();
+ m_tle = tle;
+ }
+ }
+
+ QString toString()
+ {
+ QStringList list;
+ list.append(QString("Name: %1").arg(m_name));
+ list.append(QString("NORAD ID: %1").arg(m_noradCatId));
+ if (m_tle != nullptr)
+ {
+ list.append(QString("TLE0: %1").arg(m_tle->m_tle0));
+ list.append(QString("TLE1: %1").arg(m_tle->m_tle1));
+ list.append(QString("TLE2: %1").arg(m_tle->m_tle2));
+ }
+ for (int i = 0; i < m_transmitters.size(); i++)
+ {
+ list.append(QString("Mode: %1 Freq: %2").arg(m_transmitters[i]->m_mode).arg(m_transmitters[i]->m_downlinkLow));
+ }
+ return list.join("\n");
+ }
+
+ void addTransmitters(const QList& transmitters)
+ {
+ for (int i = 0; i < transmitters.size(); i++)
+ {
+ SatNogsTransmitter *tx = transmitters[i];
+ if (tx->m_noradCatId == m_noradCatId)
+ m_transmitters.append(tx);
+ }
+ }
+
+ void addTLE(const QList& tles)
+ {
+ for (int i = 0; i < tles.size(); i++)
+ {
+ SatNogsTLE *tle = tles[i];
+ if (tle->m_noradCatId == m_noradCatId)
+ m_tle = tle;
+ }
+ }
+
+ // Create a hash table of satellites from the JSON object
+ static QHash createHash(QJsonArray array)
+ {
+ QHash hash;
+
+ for (int i = 0; i < array.size(); i++)
+ {
+ QJsonValue value = array.at(i);
+ if (value.isObject())
+ {
+ SatNogsSatellite *sat = new SatNogsSatellite(value.toObject());
+ hash.insert(sat->m_name, sat);
+ }
+ }
+ return hash;
+ }
+
+};
+
+
+#endif // INCLUDE_SATNOGS_H_
diff --git a/plugins/feature/startracker/startrackergui.cpp b/plugins/feature/startracker/startrackergui.cpp
index e707a07c6..95e13f8ba 100644
--- a/plugins/feature/startracker/startrackergui.cpp
+++ b/plugins/feature/startracker/startrackergui.cpp
@@ -43,6 +43,17 @@
#include "startrackerreport.h"
#include "startrackersettingsdialog.h"
+// Linear extrapolation
+static double extrapolate(double x0, double y0, double x1, double y1, double x)
+{
+ return y0 + ((x-x0)/(x1-x0)) * (y1-y0);
+}
+
+// Linear interpolation
+static double interpolate(double x0, double y0, double x1, double y1, double x)
+{
+ return (y0*(x1-x) + y1*(x-x0)) / (x1-x0);
+}
StarTrackerGUI* StarTrackerGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
{
@@ -153,8 +164,9 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
m_featureUISet(featureUISet),
m_doApplySettings(true),
m_lastFeatureState(0),
+ m_azElLineChart(nullptr),
+ m_azElPolarChart(nullptr),
m_networkManager(nullptr),
- m_progressDialog(nullptr),
m_solarFlux(0.0),
m_solarFluxesValid(false),
m_images{QImage(":/startracker/startracker/150mhz_ra_dec.png"),
@@ -194,6 +206,16 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
m_chart.layout()->setContentsMargins(0, 0, 0, 0);
m_chart.setMargins(QMargins(1, 1, 1, 1));
+ m_solarFluxChart.setTitle("");
+ m_solarFluxChart.legend()->hide();
+ m_solarFluxChart.addAxis(&m_chartSolarFluxXAxis, Qt::AlignBottom);
+ m_solarFluxChart.addAxis(&m_chartSolarFluxYAxis, Qt::AlignLeft);
+ m_solarFluxChart.layout()->setContentsMargins(0, 0, 0, 0);
+ m_solarFluxChart.setMargins(QMargins(1, 1, 1, 1));
+ m_chartSolarFluxXAxis.setTitleText(QString("Frequency (MHz)"));
+ m_chartSolarFluxXAxis.setMinorTickCount(-1);
+ m_chartSolarFluxYAxis.setTitleText(QString("Solar flux density (%1)").arg(solarFluxUnit()));
+
// Create axes that are static
m_skyTempGalacticLXAxis.setTitleText(QString("Galactic longitude (%1)").arg(QChar(0xb0)));
@@ -230,6 +252,9 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
displaySettings();
applySettings(true);
+ // Populate subchart menu
+ on_chartSelect_currentIndexChanged(0);
+
// Use My Position from preferences, if none set
if ((m_settings.m_latitude == 0.0) && (m_settings.m_longitude == 0.0))
on_useMyPosition_clicked();
@@ -580,7 +605,12 @@ void StarTrackerGUI::on_dateTime_dateTimeChanged(const QDateTime &datetime)
void StarTrackerGUI::plotChart()
{
if (ui->chartSelect->currentIndex() == 0)
- plotElevationChart();
+ {
+ if (ui->chartSubSelect->currentIndex() == 0)
+ plotElevationLineChart();
+ else
+ plotElevationPolarChart();
+ }
else if (ui->chartSelect->currentIndex() == 1)
plotSolarFluxChart();
else if (ui->chartSelect->currentIndex() == 2)
@@ -616,8 +646,7 @@ void StarTrackerGUI::on_beamwidth_valueChanged(double value)
void StarTrackerGUI::plotSolarFluxChart()
{
- m_chart.removeAllSeries();
- removeAllAxes();
+ m_solarFluxChart.removeAllSeries();
if (m_solarFluxesValid)
{
double maxValue = -std::numeric_limits::infinity();
@@ -633,35 +662,30 @@ void StarTrackerGUI::plotSolarFluxChart()
series->setPointLabelsVisible(true);
series->setPointLabelsFormat("@yPoint");
series->setPointLabelsClipping(false);
- m_chart.setTitle("");
- m_chart.addAxis(&m_chartSolarFluxXAxis, Qt::AlignBottom);
- m_chart.addAxis(&m_chartYAxis, Qt::AlignLeft);
- m_chart.addSeries(series);
+ m_solarFluxChart.addSeries(series);
series->attachAxis(&m_chartSolarFluxXAxis);
- series->attachAxis(&m_chartYAxis);
- m_chartSolarFluxXAxis.setTitleText(QString("Frequency (MHz)"));
- m_chartSolarFluxXAxis.setMinorTickCount(-1);
+ series->attachAxis(&m_chartSolarFluxYAxis);
if (m_settings.m_solarFluxUnits == StarTrackerSettings::SFU)
{
- m_chartYAxis.setLabelFormat("%d");
- m_chartYAxis.setRange(0.0, ((((int)maxValue)+99)/100)*100);
+ m_chartSolarFluxYAxis.setLabelFormat("%d");
+ m_chartSolarFluxYAxis.setRange(0.0, ((((int)maxValue)+99)/100)*100);
}
else if (m_settings.m_solarFluxUnits == StarTrackerSettings::JANSKY)
{
- m_chartYAxis.setLabelFormat("%.2g");
- m_chartYAxis.setRange(0, ((((int)maxValue)+999999)/100000)*100000);
+ m_chartSolarFluxYAxis.setLabelFormat("%.2g");
+ m_chartSolarFluxYAxis.setRange(0, ((((int)maxValue)+999999)/100000)*100000);
}
else
{
- m_chartYAxis.setLabelFormat("%.2g");
- m_chartYAxis.setRange(minValue, maxValue);
+ m_chartSolarFluxYAxis.setLabelFormat("%.2g");
+ m_chartSolarFluxYAxis.setRange(minValue, maxValue);
}
- m_chartYAxis.setTitleText(QString("Solar flux density (%1)").arg(solarFluxUnit()));
}
else
- m_chart.setTitle("Press download Solar flux density data to view");
- m_chart.setPlotAreaBackgroundVisible(false);
- disconnect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
+ m_solarFluxChart.setTitle("Press download Solar flux density data to view");
+ ui->chart->setChart(&m_solarFluxChart);
+// m_chart.setPlotAreaBackgroundVisible(false);
+// disconnect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
}
void StarTrackerGUI::plotSkyTemperatureChart()
@@ -875,7 +899,7 @@ void StarTrackerGUI::plotSkyTemperatureChart()
m_chart.addAxis(&m_skyTempYAxis, Qt::AlignLeft);
series->attachAxis(&m_skyTempYAxis);
}
-
+ ui->chart->setChart(&m_chart);
plotAreaChanged(m_chart.plotArea());
connect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
}
@@ -915,14 +939,29 @@ void StarTrackerGUI::removeAllAxes()
}
// Plot target elevation angle over the day
-void StarTrackerGUI::plotElevationChart()
+void StarTrackerGUI::plotElevationLineChart()
{
- m_chart.removeAllSeries();
- removeAllAxes();
+ QChart *oldChart = m_azElLineChart;
+
+ m_azElLineChart = new QChart();
+ QDateTimeAxis *xAxis = new QDateTimeAxis();
+ QValueAxis *yLeftAxis = new QValueAxis();
+ QValueAxis *yRightAxis = new QValueAxis();
+
+ m_azElLineChart->legend()->hide();
+
+ m_azElLineChart->layout()->setContentsMargins(0, 0, 0, 0);
+ m_azElLineChart->setMargins(QMargins(1, 1, 1, 1));
double maxElevation = -90.0;
- QLineSeries *series = new QLineSeries();
+ QLineSeries *elSeries = new QLineSeries();
+ QList azSeriesList;
+ QLineSeries *azSeries = new QLineSeries();
+ azSeriesList.append(azSeries);
+ QPen pen(QColor(153, 202, 83), 2, Qt::SolidLine);
+ azSeries->setPen(pen);
+
QDateTime dt;
if (m_settings.m_dateTime.isEmpty())
dt = QDateTime::currentDateTime();
@@ -931,7 +970,9 @@ void StarTrackerGUI::plotElevationChart()
dt.setTime(QTime(0,0));
QDateTime startTime = dt;
QDateTime endTime = dt;
- for (int hour = 0; hour <= 24; hour++)
+ double prevAz;
+ int timestep = 10*60;
+ for (int step = 0; step <= 24*60*60/timestep; step++)
{
AzAlt aa;
RADec rd;
@@ -967,28 +1008,239 @@ void StarTrackerGUI::plotElevationChart()
aa.alt = 90.0f;
}
- series->append(dt.toMSecsSinceEpoch(), aa.alt);
+ if (step == 0)
+ prevAz = aa.az;
+
+ if (((prevAz >= 270) && (aa.az < 90)) || ((prevAz < 90) && (aa.az >= 270)))
+ {
+ azSeries = new QLineSeries();
+ azSeriesList.append(azSeries);
+ azSeries->setPen(pen);
+ }
+
+ elSeries->append(dt.toMSecsSinceEpoch(), aa.alt);
+ azSeries->append(dt.toMSecsSinceEpoch(), aa.az);
endTime = dt;
- dt = dt.addSecs(60*60); // addSecs accounts for daylight savings jumps
+ prevAz = aa.az;
+ dt = dt.addSecs(timestep); // addSecs accounts for daylight savings jumps
}
+ m_azElLineChart->addAxis(xAxis, Qt::AlignBottom);
+ m_azElLineChart->addAxis(yLeftAxis, Qt::AlignLeft);
+ m_azElLineChart->addAxis(yRightAxis, Qt::AlignRight);
+ m_azElLineChart->addSeries(elSeries);
+ for (int i = 0; i < azSeriesList.size(); i++)
+ {
+ m_azElLineChart->addSeries(azSeriesList[i]);
+ azSeriesList[i]->attachAxis(xAxis);
+ azSeriesList[i]->attachAxis(yRightAxis);
+ }
+ elSeries->attachAxis(xAxis);
+ elSeries->attachAxis(yLeftAxis);
+ xAxis->setTitleText(QString("%1 %2").arg(startTime.date().toString()).arg(startTime.timeZoneAbbreviation()));
+ xAxis->setFormat("hh");
+ xAxis->setTickCount(7);
+ xAxis->setRange(startTime, endTime);
+ yLeftAxis->setRange(0.0, 90.0);
+ yLeftAxis->setTitleText(QString("Elevation (%1)").arg(QChar(0xb0)));
+ yRightAxis->setRange(0.0, 360.0);
+ yRightAxis->setTitleText(QString("Azimuth (%1)").arg(QChar(0xb0)));
if (maxElevation < 0)
- m_chart.setTitle("Not visible from this latitude");
+ m_azElLineChart->setTitle("Not visible from this latitude");
else
- m_chart.setTitle("");
- m_chart.addAxis(&m_chartXAxis, Qt::AlignBottom);
- m_chart.addAxis(&m_chartYAxis, Qt::AlignLeft);
- m_chart.addSeries(series);
- series->attachAxis(&m_chartXAxis);
- series->attachAxis(&m_chartYAxis);
- m_chartXAxis.setTitleText(QString("%1 %2").arg(startTime.date().toString()).arg(startTime.timeZoneAbbreviation()));
- m_chartXAxis.setFormat("hh");
- m_chartXAxis.setTickCount(7);
- m_chartXAxis.setRange(startTime, endTime);
- m_chartYAxis.setRange(0.0, 90.0);
- m_chartYAxis.setTitleText(QString("Elevation (%1)").arg(QChar(0xb0)));
- m_chart.setPlotAreaBackgroundVisible(false);
- disconnect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
+ m_azElLineChart->setTitle("");
+ ui->chart->setChart(m_azElLineChart);
+
+ delete oldChart;
+}
+
+// Plot target elevation angle over the day
+void StarTrackerGUI::plotElevationPolarChart()
+{
+ QChart *oldChart = m_azElPolarChart;
+
+ m_azElPolarChart = new QPolarChart();
+ QValueAxis *angularAxis = new QValueAxis();
+ QCategoryAxis *radialAxis = new QCategoryAxis();
+
+ angularAxis->setTickCount(9);
+ angularAxis->setMinorTickCount(1);
+ angularAxis->setLabelFormat("%d");
+ angularAxis->setRange(0, 360);
+
+ radialAxis->setMin(0);
+ radialAxis->setMax(90);
+ radialAxis->append("90", 0);
+ radialAxis->append("60", 30);
+ radialAxis->append("30", 60);
+ radialAxis->append("0", 90);
+ radialAxis->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
+
+ m_azElPolarChart->addAxis(angularAxis, QPolarChart::PolarOrientationAngular);
+ m_azElPolarChart->addAxis(radialAxis, QPolarChart::PolarOrientationRadial);
+ m_azElPolarChart->legend()->hide();
+ m_azElPolarChart->layout()->setContentsMargins(0, 0, 0, 0);
+ m_azElPolarChart->setMargins(QMargins(1, 1, 1, 1));
+
+ double maxElevation = -90.0;
+
+ QLineSeries *polarSeries = new QLineSeries();
+ QDateTime dt;
+ if (m_settings.m_dateTime.isEmpty())
+ dt = QDateTime::currentDateTime();
+ else
+ dt = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
+ dt.setTime(QTime(0,0));
+ QDateTime startTime = dt;
+ QDateTime endTime = dt;
+ QDateTime riseTime;
+ QDateTime setTime;
+ int riseIdx = -1;
+ int setIdx = -1;
+ int idx = 0;
+ int timestep = 10*60; // Rise/set times accurate to nearest 10 minutes
+ double prevAlt;
+ for (int step = 0; step <= 24*60*60/timestep; step++)
+ {
+ AzAlt aa;
+ RADec rd;
+
+ // Calculate elevation of desired object
+ if (m_settings.m_target == "Sun")
+ Astronomy::sunPosition(aa, rd, m_settings.m_latitude, m_settings.m_longitude, dt);
+ else if (m_settings.m_target == "Moon")
+ Astronomy::moonPosition(aa, rd, m_settings.m_latitude, m_settings.m_longitude, dt);
+ else
+ {
+ rd.ra = Astronomy::raToDecimal(m_settings.m_ra);
+ rd.dec = Astronomy::decToDecimal(m_settings.m_dec);
+ aa = Astronomy::raDecToAzAlt(rd, m_settings.m_latitude, m_settings.m_longitude, dt, !m_settings.m_jnow);
+ }
+
+ if (aa.alt > maxElevation)
+ maxElevation = aa.alt;
+
+ // Adjust for refraction
+ if (m_settings.m_refraction == "Positional Astronomy Library")
+ {
+ aa.alt += Astronomy::refractionPAL(aa.alt, m_settings.m_pressure, m_settings.m_temperature, m_settings.m_humidity,
+ m_settings.m_frequency, m_settings.m_latitude, m_settings.m_heightAboveSeaLevel,
+ m_settings.m_temperatureLapseRate);
+ if (aa.alt > 90.0)
+ aa.alt = 90.0f;
+ }
+ else if (m_settings.m_refraction == "Saemundsson")
+ {
+ aa.alt += Astronomy::refractionSaemundsson(aa.alt, m_settings.m_pressure, m_settings.m_temperature);
+ if (aa.alt > 90.0)
+ aa.alt = 90.0f;
+ }
+
+ if (idx == 0)
+ prevAlt = aa.alt;
+
+ // We can have set before rise in a day, if the object starts > 0
+ if ((aa.alt >= 0.0) && (prevAlt < 0.0))
+ {
+ riseTime = dt;
+ riseIdx = idx;
+ }
+ if ((aa.alt < 0.0) && (prevAlt >= 0.0))
+ {
+ setTime = endTime;
+ setIdx = idx;
+ }
+
+ polarSeries->append(aa.az, 90 - aa.alt);
+ idx++;
+
+ endTime = dt;
+ prevAlt = aa.alt;
+
+ dt = dt.addSecs(timestep); // addSecs accounts for daylight savings jumps
+ }
+
+ // Polar charts can't handle points that are more than 180 degrees apart, so
+ // we need to split passes that cross from 359 -> 0 degrees (or the reverse)
+ QList series;
+ series.append(new QLineSeries());
+ QLineSeries *s = series.first();
+ QPen pen(QColor(32, 159, 223), 2, Qt::SolidLine);
+ s->setPen(pen);
+
+ qreal prevAz = polarSeries->at(0).x();
+ qreal prevEl = polarSeries->at(0).y();
+ for (int i = 1; i < polarSeries->count(); i++)
+ {
+ qreal az = polarSeries->at(i).x();
+ qreal el = polarSeries->at(i).y();
+ if ((prevAz > 270.0) && (az <= 90.0))
+ {
+ double elMid = interpolate(prevAz, prevEl, az+360.0, el, 360.0);
+ s->append(360.0, elMid);
+ series.append(new QLineSeries());
+ s = series.last();
+ s->setPen(pen);
+ s->append(0.0, elMid);
+ s->append(az, el);
+ }
+ else if ((prevAz <= 90.0) && (az > 270.0))
+ {
+ double elMid = interpolate(prevAz, prevEl, az-360.0, el, 0.0);
+ s->append(0.0, elMid);
+ series.append(new QLineSeries());
+ s = series.last();
+ s->setPen(pen);
+ s->append(360.0, elMid);
+ s->append(az, el);
+ }
+ else
+ s->append(polarSeries->at(i));
+ prevAz = az;
+ prevEl = el;
+ }
+
+ for (int i = 0; i < series.length(); i++)
+ {
+ m_azElPolarChart->addSeries(series[i]);
+ series[i]->attachAxis(angularAxis);
+ series[i]->attachAxis(radialAxis);
+ }
+
+ // Create series with single point, so we can plot time of rising
+ if (riseTime.isValid())
+ {
+ QLineSeries *riseSeries = new QLineSeries();
+ riseSeries->append(polarSeries->at(riseIdx));
+ riseSeries->setPointLabelsFormat(QString("Rise %1").arg(riseTime.time().toString("hh:mm")));
+ riseSeries->setPointLabelsVisible(true);
+ riseSeries->setPointLabelsClipping(false);
+ m_azElPolarChart->addSeries(riseSeries);
+ riseSeries->attachAxis(angularAxis);
+ riseSeries->attachAxis(radialAxis);
+ }
+
+ // Create series with single point, so we can plot time of setting
+ if (setTime.isValid())
+ {
+ QLineSeries *setSeries = new QLineSeries();
+ setSeries->append(polarSeries->at(setIdx));
+ setSeries->setPointLabelsFormat(QString("Set %1").arg(setTime.time().toString("hh:mm")));
+ setSeries->setPointLabelsVisible(true);
+ setSeries->setPointLabelsClipping(false);
+ m_azElPolarChart->addSeries(setSeries);
+ setSeries->attachAxis(angularAxis);
+ setSeries->attachAxis(radialAxis);
+ }
+
+ if (maxElevation < 0)
+ m_azElPolarChart->setTitle("Not visible from this latitude");
+ else
+ m_azElPolarChart->setTitle("");
+ ui->chart->setChart(m_azElPolarChart);
+
+ delete polarSeries;
+ delete oldChart;
}
// Find target on the Map
@@ -1017,7 +1269,12 @@ void StarTrackerGUI::on_chartSelect_currentIndexChanged(int index)
{
bool oldState = ui->chartSubSelect->blockSignals(true);
ui->chartSubSelect->clear();
- if (index == 2)
+ if (index == 0)
+ {
+ ui->chartSubSelect->addItem("Az/El vs time");
+ ui->chartSubSelect->addItem("Polar");
+ }
+ else if (index == 2)
{
ui->chartSubSelect->addItem(QString("150 MHz 5%1 Equatorial").arg(QChar(0xb0)));
ui->chartSubSelect->addItem(QString("150 MHz 5%1 Galactic").arg(QChar(0xb0)));
@@ -1068,18 +1325,6 @@ QString StarTrackerGUI::solarFluxUnit()
return "";
}
-// Linear extrapolation
-static double extrapolate(double x0, double y0, double x1, double y1, double x)
-{
- return y0 + ((x-x0)/(x1-x0)) * (y1-y0);
-}
-
-// Linear interpolation
-static double interpolate(double x0, double y0, double x1, double y1, double x)
-{
- return (y0*(x1-x) + y1*(x-x0)) / (x1-x0);
-}
-
void StarTrackerGUI::displaySolarFlux()
{
if (((m_settings.m_solarFluxData == StarTrackerSettings::DRAO_2800) && (m_solarFlux == 0.0))
diff --git a/plugins/feature/startracker/startrackergui.h b/plugins/feature/startracker/startrackergui.h
index b20833ef6..316e2c4b4 100644
--- a/plugins/feature/startracker/startrackergui.h
+++ b/plugins/feature/startracker/startrackergui.h
@@ -67,6 +67,9 @@ private:
QTimer m_solarFluxTimer;
int m_lastFeatureState;
+ QChart *m_azElLineChart;
+ QPolarChart *m_azElPolarChart;
+
QChart m_chart;
QDateTimeAxis m_chartXAxis;
QValueAxis m_chartYAxis;
@@ -75,12 +78,13 @@ private:
QCategoryAxis m_skyTempRAXAxis;
QValueAxis m_skyTempYAxis;
+ QChart m_solarFluxChart;
QLogValueAxis m_chartSolarFluxXAxis;
+ QValueAxis m_chartSolarFluxYAxis;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
HttpDownloadManagerGUI m_dlm;
- QProgressDialog *m_progressDialog;
double m_solarFlux; // 10.7cm/2800MHz
bool m_solarFluxesValid;
@@ -101,7 +105,8 @@ private:
QString convertDegreesToText(double degrees);
bool handleMessage(const Message& message);
void updateLST();
- void plotElevationChart();
+ void plotElevationLineChart();
+ void plotElevationPolarChart();
void plotSkyTemperatureChart();
void plotSolarFluxChart();
void plotChart();
diff --git a/plugins/feature/startracker/startrackergui.ui b/plugins/feature/startracker/startrackergui.ui
index 2157dee50..95944389b 100644
--- a/plugins/feature/startracker/startrackergui.ui
+++ b/plugins/feature/startracker/startrackergui.ui
@@ -109,7 +109,7 @@
-
+ Date and time to use when calculating target's position
@@ -313,7 +313,7 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
- start/stop acquisition
+ Start/stop tracking
@@ -339,7 +339,7 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
-
+ Find target on the map
@@ -353,7 +353,7 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
-
+ Download Solar flux density data
@@ -367,7 +367,7 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
-
+ Set latitude, longitude and height from My Position in SDRangel preferences
@@ -381,7 +381,7 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
-
+ Show settings dialog
@@ -595,10 +595,17 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
QGraphicsViewQtCharts
+
+ WrappingDateTimeEdit
+ QDateTimeEdit
+ gui/wrappingdatetimeedit.h
+ 1
+ startStopviewOnMap
+ downloadSolarFluxuseMyPositiondisplaySettingslatitude
@@ -608,10 +615,14 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
lstsolarFluxtarget
+ frequency
+ beamwidthrightAscensiondeclinationazimuthelevation
+ chartSelect
+ chartSubSelectchart
diff --git a/sdrbase/channel/channelwebapiutils.cpp b/sdrbase/channel/channelwebapiutils.cpp
index 62a104a21..9f27394a4 100644
--- a/sdrbase/channel/channelwebapiutils.cpp
+++ b/sdrbase/channel/channelwebapiutils.cpp
@@ -25,20 +25,24 @@
#include "SWGDeviceSettings.h"
#include "SWGChannelSettings.h"
#include "SWGDeviceSet.h"
+#include "SWGChannelActions.h"
+#include "SWGFileSinkActions.h"
#include "maincore.h"
#include "device/deviceset.h"
#include "device/deviceapi.h"
+#include "channel/channelutils.h"
#include "dsp/devicesamplesource.h"
#include "dsp/devicesamplesink.h"
#include "dsp/devicesamplemimo.h"
#include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h"
+// Get device center frequency
bool ChannelWebAPIUtils::getCenterFrequency(unsigned int deviceIndex, double &frequencyInHz)
{
SWGSDRangel::SWGDeviceSettings deviceSettingsResponse;
- SWGSDRangel::SWGErrorResponse errorResponse;
+ QString errorResponse;
int httpRC;
DeviceSet *deviceSet;
@@ -52,21 +56,21 @@ bool ChannelWebAPIUtils::getCenterFrequency(unsigned int deviceIndex, double &fr
deviceSettingsResponse.setDeviceHwType(new QString(deviceSet->m_deviceAPI->getHardwareId()));
deviceSettingsResponse.setDirection(0);
DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
- httpRC = source->webapiSettingsGet(deviceSettingsResponse, *errorResponse.getMessage());
+ httpRC = source->webapiSettingsGet(deviceSettingsResponse, errorResponse);
}
else if (deviceSet->m_deviceSinkEngine)
{
deviceSettingsResponse.setDeviceHwType(new QString(deviceSet->m_deviceAPI->getHardwareId()));
deviceSettingsResponse.setDirection(1);
DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink();
- httpRC = sink->webapiSettingsGet(deviceSettingsResponse, *errorResponse.getMessage());
+ httpRC = sink->webapiSettingsGet(deviceSettingsResponse, errorResponse);
}
else if (deviceSet->m_deviceMIMOEngine)
{
deviceSettingsResponse.setDeviceHwType(new QString(deviceSet->m_deviceAPI->getHardwareId()));
deviceSettingsResponse.setDirection(2);
DeviceSampleMIMO *mimo = deviceSet->m_deviceAPI->getSampleMIMO();
- httpRC = mimo->webapiSettingsGet(deviceSettingsResponse, *errorResponse.getMessage());
+ httpRC = mimo->webapiSettingsGet(deviceSettingsResponse, errorResponse);
}
else
{
@@ -83,7 +87,7 @@ bool ChannelWebAPIUtils::getCenterFrequency(unsigned int deviceIndex, double &fr
if (httpRC/100 != 2)
{
qWarning("ChannelWebAPIUtils::getCenterFrequency: get device frequency error %d: %s",
- httpRC, qPrintable(*errorResponse.getMessage()));
+ httpRC, qPrintable(errorResponse));
return false;
}
@@ -91,10 +95,11 @@ bool ChannelWebAPIUtils::getCenterFrequency(unsigned int deviceIndex, double &fr
return WebAPIUtils::getSubObjectDouble(*jsonObj, "centerFrequency", frequencyInHz);
}
+// Set device center frequency
bool ChannelWebAPIUtils::setCenterFrequency(unsigned int deviceIndex, double frequencyInHz)
{
SWGSDRangel::SWGDeviceSettings deviceSettingsResponse;
- SWGSDRangel::SWGErrorResponse errorResponse;
+ QString errorResponse;
int httpRC;
DeviceSet *deviceSet;
@@ -108,21 +113,21 @@ bool ChannelWebAPIUtils::setCenterFrequency(unsigned int deviceIndex, double fre
deviceSettingsResponse.setDeviceHwType(new QString(deviceSet->m_deviceAPI->getHardwareId()));
deviceSettingsResponse.setDirection(0);
DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
- httpRC = source->webapiSettingsGet(deviceSettingsResponse, *errorResponse.getMessage());
+ httpRC = source->webapiSettingsGet(deviceSettingsResponse, errorResponse);
}
else if (deviceSet->m_deviceSinkEngine)
{
deviceSettingsResponse.setDeviceHwType(new QString(deviceSet->m_deviceAPI->getHardwareId()));
deviceSettingsResponse.setDirection(1);
DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink();
- httpRC = sink->webapiSettingsGet(deviceSettingsResponse, *errorResponse.getMessage());
+ httpRC = sink->webapiSettingsGet(deviceSettingsResponse, errorResponse);
}
else if (deviceSet->m_deviceMIMOEngine)
{
deviceSettingsResponse.setDeviceHwType(new QString(deviceSet->m_deviceAPI->getHardwareId()));
deviceSettingsResponse.setDirection(2);
DeviceSampleMIMO *mimo = deviceSet->m_deviceAPI->getSampleMIMO();
- httpRC = mimo->webapiSettingsGet(deviceSettingsResponse, *errorResponse.getMessage());
+ httpRC = mimo->webapiSettingsGet(deviceSettingsResponse, errorResponse);
}
else
{
@@ -139,7 +144,7 @@ bool ChannelWebAPIUtils::setCenterFrequency(unsigned int deviceIndex, double fre
if (httpRC/100 != 2)
{
qWarning("ChannelWebAPIUtils::setCenterFrequency: get device frequency error %d: %s",
- httpRC, qPrintable(*errorResponse.getMessage()));
+ httpRC, qPrintable(errorResponse));
return false;
}
@@ -178,3 +183,282 @@ bool ChannelWebAPIUtils::setCenterFrequency(unsigned int deviceIndex, double fre
return true;
}
+
+// Start acquisition
+bool ChannelWebAPIUtils::run(unsigned int deviceIndex, int subsystemIndex)
+{
+ SWGSDRangel::SWGDeviceState runResponse;
+ QString errorResponse;
+ int httpRC;
+ DeviceSet *deviceSet;
+
+ std::vector deviceSets = MainCore::instance()->getDeviceSets();
+ if (deviceIndex < deviceSets.size())
+ {
+ runResponse.setState(new QString());
+ deviceSet = deviceSets[deviceIndex];
+ if (deviceSet->m_deviceSourceEngine)
+ {
+ DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
+ httpRC = source->webapiRun(1, runResponse, errorResponse);
+ }
+ else if (deviceSet->m_deviceSinkEngine)
+ {
+ DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink();
+ httpRC = sink->webapiRun(1, runResponse, errorResponse);
+ }
+ else if (deviceSet->m_deviceMIMOEngine)
+ {
+ DeviceSampleMIMO *mimo = deviceSet->m_deviceAPI->getSampleMIMO();
+ httpRC = mimo->webapiRun(1, subsystemIndex, runResponse, errorResponse);
+ }
+ else
+ {
+ qDebug() << "ChannelWebAPIUtils::run - unknown device " << deviceIndex;
+ return false;
+ }
+ }
+ else
+ {
+ qDebug() << "ChannelWebAPIUtils::run - no device " << deviceIndex;
+ return false;
+ }
+
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::run: run error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+
+ return true;
+}
+
+// Stop acquisition
+bool ChannelWebAPIUtils::stop(unsigned int deviceIndex, int subsystemIndex)
+{
+ SWGSDRangel::SWGDeviceState runResponse;
+ QString errorResponse;
+ int httpRC;
+ DeviceSet *deviceSet;
+
+ std::vector deviceSets = MainCore::instance()->getDeviceSets();
+ if (deviceIndex < deviceSets.size())
+ {
+ runResponse.setState(new QString());
+ deviceSet = deviceSets[deviceIndex];
+ if (deviceSet->m_deviceSourceEngine)
+ {
+ DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
+ httpRC = source->webapiRun(0, runResponse, errorResponse);
+ }
+ else if (deviceSet->m_deviceSinkEngine)
+ {
+ DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink();
+ httpRC = sink->webapiRun(0, runResponse, errorResponse);
+ }
+ else if (deviceSet->m_deviceMIMOEngine)
+ {
+ DeviceSampleMIMO *mimo = deviceSet->m_deviceAPI->getSampleMIMO();
+ httpRC = mimo->webapiRun(0, subsystemIndex, runResponse, errorResponse);
+ }
+ else
+ {
+ qDebug() << "ChannelWebAPIUtils::stop - unknown device " << deviceIndex;
+ return false;
+ }
+ }
+ else
+ {
+ qDebug() << "ChannelWebAPIUtils::stop - no device " << deviceIndex;
+ return false;
+ }
+
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::stop: run error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+
+ return true;
+}
+
+// Get input frequency offset for a channel
+bool ChannelWebAPIUtils::getFrequencyOffset(unsigned int deviceIndex, int channelIndex, int& offset)
+{
+ SWGSDRangel::SWGChannelSettings channelSettingsResponse;
+ QString errorResponse;
+ int httpRC;
+ QJsonObject *jsonObj;
+ double offsetD;
+
+ ChannelAPI *channel = MainCore::instance()->getChannel(deviceIndex, channelIndex);
+ if (channel != nullptr)
+ {
+ httpRC = channel->webapiSettingsGet(channelSettingsResponse, errorResponse);
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::getFrequencyOffset: get channel settings error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+
+ jsonObj = channelSettingsResponse.asJsonObject();
+ if (WebAPIUtils::getSubObjectDouble(*jsonObj, "inputFrequencyOffset", offsetD))
+ {
+ offset = (int)offsetD;
+ return true;
+ }
+ }
+ return false;
+}
+
+// Set input frequency offset for a channel
+bool ChannelWebAPIUtils::setFrequencyOffset(unsigned int deviceIndex, int channelIndex, int offset)
+{
+ SWGSDRangel::SWGChannelSettings channelSettingsResponse;
+ QString errorResponse;
+ int httpRC;
+ QJsonObject *jsonObj;
+
+ ChannelAPI *channel = MainCore::instance()->getChannel(deviceIndex, channelIndex);
+ if (channel != nullptr)
+ {
+ httpRC = channel->webapiSettingsGet(channelSettingsResponse, errorResponse);
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::setFrequencyOffset: get channel settings error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+
+ jsonObj = channelSettingsResponse.asJsonObject();
+
+ if (WebAPIUtils::setSubObjectDouble(*jsonObj, "inputFrequencyOffset", (double)offset))
+ {
+ QStringList keys;
+ keys.append("inputFrequencyOffset");
+ channelSettingsResponse.init();
+ channelSettingsResponse.fromJsonObject(*jsonObj);
+ httpRC = channel->webapiSettingsPutPatch(false, keys, channelSettingsResponse, errorResponse);
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::setFrequencyOffset: patch channel settings error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+// Start or stop all file sinks in a given device set
+bool ChannelWebAPIUtils::startStopFileSinks(unsigned int deviceIndex, bool start)
+{
+ MainCore *mainCore = MainCore::instance();
+ ChannelAPI *channel;
+ int channelIndex = 0;
+ while(nullptr != (channel = mainCore->getChannel(deviceIndex, channelIndex)))
+ {
+ if (ChannelUtils::compareChannelURIs(channel->getURI(), "sdrangel.channel.filesink"))
+ {
+ QStringList channelActionKeys = {"record"};
+ SWGSDRangel::SWGChannelActions channelActions;
+ SWGSDRangel::SWGFileSinkActions *fileSinkAction = new SWGSDRangel::SWGFileSinkActions();
+ QString errorResponse;
+ int httpRC;
+
+ fileSinkAction->setRecord(start);
+ channelActions.setFileSinkActions(fileSinkAction);
+ httpRC = channel->webapiActionsPost(channelActionKeys, channelActions, errorResponse);
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::startStopFileSinks: webapiActionsPost error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+ }
+ channelIndex++;
+ }
+ return true;
+}
+
+// Send AOS actions to all channels that support it
+bool ChannelWebAPIUtils::satelliteAOS(const QString name, bool northToSouthPass)
+{
+ MainCore *mainCore = MainCore::instance();
+ std::vector deviceSets = mainCore->getDeviceSets();
+ for (unsigned int deviceIndex = 0; deviceIndex < deviceSets.size(); deviceIndex++)
+ {
+ ChannelAPI *channel;
+ int channelIndex = 0;
+ while(nullptr != (channel = mainCore->getChannel(deviceIndex, channelIndex)))
+ {
+ if (ChannelUtils::compareChannelURIs(channel->getURI(), "sdrangel.channel.aptdemod"))
+ {
+ QStringList channelActionKeys = {"aos"};
+ SWGSDRangel::SWGChannelActions channelActions;
+ SWGSDRangel::SWGAPTDemodActions *aptDemodAction = new SWGSDRangel::SWGAPTDemodActions();
+ SWGSDRangel::SWGAPTDemodActions_aos *aosAction = new SWGSDRangel::SWGAPTDemodActions_aos();
+ QString errorResponse;
+ int httpRC;
+
+ aosAction->setSatelliteName(new QString(name));
+ aosAction->setNorthToSouthPass(northToSouthPass);
+ aptDemodAction->setAos(aosAction);
+
+ channelActions.setAptDemodActions(aptDemodAction);
+ httpRC = channel->webapiActionsPost(channelActionKeys, channelActions, errorResponse);
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::satelliteAOS: webapiActionsPost error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+ }
+ channelIndex++;
+ }
+ }
+ return true;
+}
+
+// Send LOS actions to all channels that support it
+bool ChannelWebAPIUtils::satelliteLOS(const QString name)
+{
+ MainCore *mainCore = MainCore::instance();
+ std::vector deviceSets = mainCore->getDeviceSets();
+ for (unsigned int deviceIndex = 0; deviceIndex < deviceSets.size(); deviceIndex++)
+ {
+ ChannelAPI *channel;
+ int channelIndex = 0;
+ while(nullptr != (channel = mainCore->getChannel(deviceIndex, channelIndex)))
+ {
+ if (ChannelUtils::compareChannelURIs(channel->getURI(), "sdrangel.channel.aptdemod"))
+ {
+ QStringList channelActionKeys = {"los"};
+ SWGSDRangel::SWGChannelActions channelActions;
+ SWGSDRangel::SWGAPTDemodActions *aptDemodAction = new SWGSDRangel::SWGAPTDemodActions();
+ SWGSDRangel::SWGAPTDemodActions_los *losAction = new SWGSDRangel::SWGAPTDemodActions_los();
+ QString errorResponse;
+ int httpRC;
+
+ losAction->setSatelliteName(new QString(name));
+ aptDemodAction->setLos(losAction);
+
+ channelActions.setAptDemodActions(aptDemodAction);
+ httpRC = channel->webapiActionsPost(channelActionKeys, channelActions, errorResponse);
+ if (httpRC/100 != 2)
+ {
+ qWarning("ChannelWebAPIUtils::satelliteLOS: webapiActionsPost error %d: %s",
+ httpRC, qPrintable(errorResponse));
+ return false;
+ }
+ }
+ channelIndex++;
+ }
+ }
+ return true;
+}
diff --git a/sdrbase/channel/channelwebapiutils.h b/sdrbase/channel/channelwebapiutils.h
index 624cf6ae6..0550ed34e 100644
--- a/sdrbase/channel/channelwebapiutils.h
+++ b/sdrbase/channel/channelwebapiutils.h
@@ -18,6 +18,8 @@
#ifndef SDRBASE_CHANNEL_CHANNELWEBAPIUTILS_H_
#define SDRBASE_CHANNEL_CHANNELWEBAPIUTILS_H_
+#include
+
#include "export.h"
class SDRBASE_API ChannelWebAPIUtils
@@ -25,6 +27,13 @@ class SDRBASE_API ChannelWebAPIUtils
public:
static bool getCenterFrequency(unsigned int deviceIndex, double &frequencyInHz);
static bool setCenterFrequency(unsigned int deviceIndex, double frequencyInHz);
+ static bool run(unsigned int deviceIndex, int subsystemIndex=0);
+ static bool stop(unsigned int deviceIndex, int subsystemIndex=0);
+ static bool getFrequencyOffset(unsigned int deviceIndex, int channelIndex, int& offset);
+ static bool setFrequencyOffset(unsigned int deviceIndex, int channelIndex, int offset);
+ static bool startStopFileSinks(unsigned int deviceIndex, bool start);
+ static bool satelliteAOS(const QString name, bool northToSouthPass);
+ static bool satelliteLOS(const QString name);
};
#endif // SDRBASE_CHANNEL_CHANNELWEBAPIUTILS_H_
diff --git a/sdrbase/feature/feature.cpp b/sdrbase/feature/feature.cpp
index 51048ac4a..d45989099 100644
--- a/sdrbase/feature/feature.cpp
+++ b/sdrbase/feature/feature.cpp
@@ -26,6 +26,7 @@
#include "maincore.h"
Feature::Feature(const QString& uri, WebAPIAdapterInterface *webAPIAdapterInterface) :
+ m_guiMessageQueue(nullptr),
m_webAPIAdapterInterface(webAPIAdapterInterface),
m_name(uri),
m_uri(uri),
diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp
index 96cc410dc..1e327f606 100644
--- a/sdrbase/plugin/pluginmanager.cpp
+++ b/sdrbase/plugin/pluginmanager.cpp
@@ -338,3 +338,28 @@ const PluginInterface *PluginManager::getFeaturePluginInterface(const QString& f
return nullptr;
}
+
+QString PluginManager::uriToId(const QString& uri) const
+{
+ for (int i = 0; i < m_rxChannelRegistrations.size(); i++)
+ {
+ if (m_rxChannelRegistrations[i].m_channelIdURI == uri)
+ return m_rxChannelRegistrations[i].m_channelId;
+ }
+ for (int i = 0; i < m_txChannelRegistrations.size(); i++)
+ {
+ if (m_txChannelRegistrations[i].m_channelIdURI == uri)
+ return m_txChannelRegistrations[i].m_channelId;
+ }
+ for (int i = 0; i < m_mimoChannelRegistrations.size(); i++)
+ {
+ if (m_mimoChannelRegistrations[i].m_channelIdURI == uri)
+ return m_mimoChannelRegistrations[i].m_channelId;
+ }
+ for (int i = 0; i < m_featureRegistrations.size(); i++)
+ {
+ if (m_featureRegistrations[i].m_featureIdURI == uri)
+ return m_featureRegistrations[i].m_featureId;
+ }
+ return uri;
+}
diff --git a/sdrbase/plugin/pluginmanager.h b/sdrbase/plugin/pluginmanager.h
index 705c38d5f..71713810c 100644
--- a/sdrbase/plugin/pluginmanager.h
+++ b/sdrbase/plugin/pluginmanager.h
@@ -89,6 +89,9 @@ public:
const PluginInterface *getDevicePluginInterface(const QString& deviceId) const;
const PluginInterface *getFeaturePluginInterface(const QString& featureIdURI) const;
+ // Map channel/feature URI to short form Id
+ QString uriToId(const QString& uri) const;
+
static const QString& getFileInputDeviceId() { return m_fileInputDeviceTypeID; }
static const QString& getTestMIMODeviceId() { return m_testMIMODeviceTypeID; }
static const QString& getFileOutputDeviceId() { return m_fileOutputDeviceTypeID; }
diff --git a/sdrbase/util/units.h b/sdrbase/util/units.h
index 877da1fe9..3f79f2dac 100644
--- a/sdrbase/util/units.h
+++ b/sdrbase/util/units.h
@@ -61,6 +61,16 @@ public:
return (int)std::round(knotsToKPH(knots));
}
+ static float kmpsToKPH(float kps)
+ {
+ return kps * (60.0 * 60.0);
+ }
+
+ static int kmpsToIntegerKPH(float kps)
+ {
+ return (int)std::round(kmpsToKPH(kps));
+ }
+
static float feetPerMinToMetresPerSecond(float fpm)
{
return fpm * 0.00508f;
diff --git a/sdrbase/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp
index d0df93b7a..2b48b7c94 100644
--- a/sdrbase/webapi/webapirequestmapper.cpp
+++ b/sdrbase/webapi/webapirequestmapper.cpp
@@ -3821,6 +3821,11 @@ bool WebAPIRequestMapper::getChannelSettings(
channelSettings->setAmModSettings(new SWGSDRangel::SWGAMModSettings());
channelSettings->getAmModSettings()->fromJsonObject(settingsJsonObject);
}
+ else if (channelSettingsKey == "APTDemodSettings")
+ {
+ channelSettings->setAptDemodSettings(new SWGSDRangel::SWGAPTDemodSettings());
+ channelSettings->getAptDemodSettings()->fromJsonObject(settingsJsonObject);
+ }
else if (channelSettingsKey == "ATVDemodSettings")
{
channelSettings->setAtvDemodSettings(new SWGSDRangel::SWGATVDemodSettings());
@@ -4008,7 +4013,12 @@ bool WebAPIRequestMapper::getChannelActions(
QJsonObject actionsJsonObject = channelActionsJson[channelActionsKey].toObject();
channelActionsKeys = actionsJsonObject.keys();
- if (channelActionsKey == "FileSinkActions")
+ if (channelActionsKey == "APTDemodActions")
+ {
+ channelActions->setAptDemodActions(new SWGSDRangel::SWGAPTDemodActions());
+ channelActions->getAptDemodActions()->fromJsonObject(actionsJsonObject);
+ }
+ else if (channelActionsKey == "FileSinkActions")
{
channelActions->setFileSinkActions(new SWGSDRangel::SWGFileSinkActions());
channelActions->getFileSinkActions()->fromJsonObject(actionsJsonObject);
@@ -4564,6 +4574,7 @@ void WebAPIRequestMapper::resetChannelSettings(SWGSDRangel::SWGChannelSettings&
channelSettings.setAdsbDemodSettings(nullptr);
channelSettings.setAmDemodSettings(nullptr);
channelSettings.setAmModSettings(nullptr);
+ channelSettings.setAptDemodSettings(nullptr);
channelSettings.setAtvModSettings(nullptr);
channelSettings.setBfmDemodSettings(nullptr);
channelSettings.setDsdDemodSettings(nullptr);
@@ -4610,6 +4621,7 @@ void WebAPIRequestMapper::resetChannelReport(SWGSDRangel::SWGChannelReport& chan
void WebAPIRequestMapper::resetChannelActions(SWGSDRangel::SWGChannelActions& channelActions)
{
channelActions.cleanup();
+ channelActions.setAptDemodActions(nullptr);
channelActions.setChannelType(nullptr);
channelActions.setFileSourceActions(nullptr);
channelActions.setIeee802154ModActions(nullptr);
diff --git a/sdrbase/webapi/webapiutils.cpp b/sdrbase/webapi/webapiutils.cpp
index 09ce7ba96..175898c23 100644
--- a/sdrbase/webapi/webapiutils.cpp
+++ b/sdrbase/webapi/webapiutils.cpp
@@ -24,6 +24,7 @@
const QMap WebAPIUtils::m_channelURIToSettingsKey = {
{"sdrangel.channel.adsbdemod", "ADSBDemodSettings"},
{"sdrangel.channel.amdemod", "AMDemodSettings"},
+ {"sdrangel.channel.aptdemod", "APTDemodSettings"},
{"de.maintech.sdrangelove.channel.am", "AMDemodSettings"}, // remap
{"sdrangel.channeltx.modam", "AMModSettings"},
{"sdrangel.channeltx.modatv", "ATVModSettings"},
@@ -47,7 +48,7 @@ const QMap WebAPIUtils::m_channelURIToSettingsKey = {
{"sdrangel.demod.localsink", "LocalSinkSettings"},
{"sdrangel.channel.localsink", "LocalSinkSettings"}, // remap
{"sdrangel.channel.localsource", "LocalSourceSettings"},
- {"sdrangel.channelrx.demodpacket", "PacketDemodSettings"},
+ {"sdrangel.channel.packetdemod", "PacketDemodSettings"},
{"sdrangel.channeltx.modpacket", "PacketModSettings"},
{"sdrangel.channeltx.mod802.15.4", "IEEE_802_15_4_ModSettings"},
{"sdrangel.demod.remotesink", "RemoteSinkSettings"},
@@ -118,6 +119,7 @@ const QMap WebAPIUtils::m_deviceIdToSettingsKey = {
const QMap WebAPIUtils::m_channelTypeToSettingsKey = {
{"ADSBDemod", "ADSBDemodSettings"},
+ {"APTDemod", "APTemodSettings"},
{"AMDemod", "AMDemodSettings"},
{"AMMod", "AMModSettings"},
{"ATVDemod", "ATVDemodSettings"},
@@ -155,6 +157,7 @@ const QMap WebAPIUtils::m_channelTypeToSettingsKey = {
};
const QMap WebAPIUtils::m_channelTypeToActionsKey = {
+ {"APTDemod", "APTDemodActions"},
{"FileSink", "FileSinkActions"},
{"FileSource", "FileSourceActions"},
{"SigMFFileSink", "SigMFFileSinkActions"},
diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt
index bc5d11e86..5a89b4b31 100644
--- a/sdrgui/CMakeLists.txt
+++ b/sdrgui/CMakeLists.txt
@@ -55,6 +55,7 @@ set(sdrgui_SOURCES
gui/samplingdevicedialog.cpp
gui/samplingdevicesdock.cpp
gui/scaleengine.cpp
+ gui/scaledimage.cpp
gui/sdrangelsplash.cpp
gui/tickedslider.cpp
gui/transverterbutton.cpp
@@ -64,6 +65,7 @@ set(sdrgui_SOURCES
gui/valuedial.cpp
gui/valuedialz.cpp
gui/wsspectrumsettingsdialog.cpp
+ gui/wrappingdatetimeedit.cpp
dsp/scopevis.cpp
dsp/scopevisxy.cpp
@@ -141,6 +143,7 @@ set(sdrgui_HEADERS
gui/samplingdevicedialog.h
gui/samplingdevicesdock.h
gui/scaleengine.h
+ gui/scaledimage.h
gui/sdrangelsplash.h
gui/tickedslider.h
gui/transverterbutton.h
@@ -150,6 +153,7 @@ set(sdrgui_HEADERS
gui/valuedial.h
gui/valuedialz.h
gui/wsspectrumsettingsdialog.h
+ gui/wrappingdatetimeedit.h
dsp/scopevis.h
dsp/scopevisxy.h
diff --git a/sdrgui/gui/scaledimage.cpp b/sdrgui/gui/scaledimage.cpp
new file mode 100644
index 000000000..365c61d39
--- /dev/null
+++ b/sdrgui/gui/scaledimage.cpp
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "scaledimage.h"
+
+ScaledImage::ScaledImage(QWidget *parent) :
+ QLabel(parent)
+{
+}
+
+void ScaledImage::setPixmap(const QPixmap& pixmap)
+{
+ setPixmap(pixmap, size());
+}
+
+void ScaledImage::setPixmap(const QPixmap& pixmap, const QSize& size)
+{
+ m_pixmap = pixmap;
+ m_pixmapScaled = pixmap.scaled(size, Qt::KeepAspectRatio);
+ QLabel::setPixmap(m_pixmapScaled);
+}
+
+void ScaledImage::resizeEvent(QResizeEvent *event)
+{
+ QLabel::resizeEvent(event);
+ setPixmap(m_pixmap, event->size());
+}
diff --git a/sdrgui/gui/scaledimage.h b/sdrgui/gui/scaledimage.h
new file mode 100644
index 000000000..b8e2a5724
--- /dev/null
+++ b/sdrgui/gui/scaledimage.h
@@ -0,0 +1,47 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRGUI_GUI_SCALEDIMAGE_H
+#define SDRGUI_GUI_SCALEDIMAGE_H
+
+#include
+#include
+#include
+#include
+
+#include "export.h"
+
+// Similar to displaying a pixmap with QLabel, except we preserve the aspect ratio
+class SDRGUI_API ScaledImage : public QLabel {
+
+public:
+ explicit ScaledImage(QWidget *parent = nullptr);
+
+ void setPixmap(const QPixmap& pixmap);
+ void setPixmap(const QPixmap& pixmap, const QSize& size);
+
+protected:
+
+ virtual void resizeEvent(QResizeEvent *event);
+
+private:
+ QPixmap m_pixmap;
+ QPixmap m_pixmapScaled;
+
+};
+
+#endif // SDRGUI_GUI_SCALEDIMAGE_H
diff --git a/sdrgui/gui/wrappingdatetimeedit.cpp b/sdrgui/gui/wrappingdatetimeedit.cpp
new file mode 100644
index 000000000..14cac8347
--- /dev/null
+++ b/sdrgui/gui/wrappingdatetimeedit.cpp
@@ -0,0 +1,71 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "wrappingdatetimeedit.h"
+
+WrappingDateTimeEdit::WrappingDateTimeEdit(QWidget *parent) :
+ QDateTimeEdit(parent)
+{
+ setWrapping(true);
+}
+
+void WrappingDateTimeEdit::stepBy(int steps)
+{
+ if (currentSection() == QDateTimeEdit::MonthSection)
+ setDate(date().addMonths(steps));
+ else if (currentSection() == QDateTimeEdit::DaySection)
+ setDate(date().addDays(steps));
+ else if (currentSection() == QDateTimeEdit::HourSection)
+ {
+ QTime t = time();
+ int h = t.hour();
+
+ setTime(time().addSecs(steps*3600));
+
+ if ((h < -steps) && (steps < 0))
+ setDate(date().addDays(-1));
+ else if ((h + steps > 23) && (steps > 0))
+ setDate(date().addDays(1));
+ }
+ else if (currentSection() == QDateTimeEdit::MinuteSection)
+ {
+ QTime t = time();
+ int h = t.hour();
+ int m = t.minute();
+
+ setTime(time().addSecs(steps*60));
+
+ if ((m < -steps) && (steps < 0) && (h == 0))
+ setDate(date().addDays(-1));
+ else if ((m + steps > 59) && (steps > 0) && (h == 23))
+ setDate(date().addDays(1));
+ }
+ else if (currentSection() == QDateTimeEdit::SecondSection)
+ {
+ QTime t = time();
+ int h = t.hour();
+ int m = t.minute();
+ int s = t.second();
+
+ setTime(time().addSecs(steps));
+
+ if ((s < -steps) && (steps < 0) && (h == 0) && (m == 0))
+ setDate(date().addDays(-1));
+ else if ((s + steps > 59) && (steps > 0) && (h == 23) && (m == 59))
+ setDate(date().addDays(1));
+ }
+}
diff --git a/sdrgui/gui/wrappingdatetimeedit.h b/sdrgui/gui/wrappingdatetimeedit.h
new file mode 100644
index 000000000..ddc766222
--- /dev/null
+++ b/sdrgui/gui/wrappingdatetimeedit.h
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2021 Jon Beniston, M7RCE //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRGUI_GUI_WRAPPINGDATETIMEEDIT_H
+#define SDRGUI_GUI_WRAPPINGDATETIMEEDIT_H
+
+#include
+
+#include "export.h"
+
+// Same as QDateTimeEdit, except allows minutes to wrap to hours and hours to
+// days when scrolling up or down
+class SDRGUI_API WrappingDateTimeEdit : public QDateTimeEdit {
+
+public:
+ explicit WrappingDateTimeEdit(QWidget *parent = nullptr);
+
+ void stepBy(int steps) override;
+};
+
+#endif // SDRGUI_GUI_WRAPPINGDATETIMEEDIT_H
diff --git a/sdrgui/resources/arrow_right.png b/sdrgui/resources/arrow_right.png
new file mode 100644
index 000000000..0ac47450d
Binary files /dev/null and b/sdrgui/resources/arrow_right.png differ
diff --git a/sdrgui/resources/res.qrc b/sdrgui/resources/res.qrc
index 5e54933c6..44b9a16c4 100644
--- a/sdrgui/resources/res.qrc
+++ b/sdrgui/resources/res.qrc
@@ -2,6 +2,7 @@
info.pngarrow_left.png
+ arrow_right.pngstar.pngswap.pnggridpolar.png
diff --git a/swagger/sdrangel/api/swagger/include/APTDemod.yaml b/swagger/sdrangel/api/swagger/include/APTDemod.yaml
new file mode 100644
index 000000000..01a7a4059
--- /dev/null
+++ b/swagger/sdrangel/api/swagger/include/APTDemod.yaml
@@ -0,0 +1,86 @@
+APTDemodSettings:
+ description: APTDemod
+ properties:
+ inputFrequencyOffset:
+ description: channel center frequency shift from baseband center in Hz
+ type: integer
+ format: int64
+ rfBandwidth:
+ description: channel RF bandwidth in Hz
+ type: number
+ format: float
+ fmDeviation:
+ description: frequency deviation in Hz
+ type: integer
+ cropNoise:
+ description: crop noise from top and bottom of image
+ type: integer
+ denoise:
+ description: apply denoise filter to image
+ type: integer
+ linearEqualise:
+ description: apply linear equalisation to image
+ type: integer
+ histogramEqualise:
+ description: apply histogram equalisation to image
+ type: integer
+ precipitationOverlay:
+ description: create colour overlay of precipitation
+ type: integer
+ flip:
+ description: flip image for South to North passes
+ type: integer
+ channels:
+ description: which channel to display (0=both, 1=A, 2=B)
+ type: integer
+ decodeEnabled:
+ description: controls whether the decoder is enabled
+ type: integer
+ autoSave:
+ description: automatically save images when acquisition is stopped
+ type: integer
+ autoSavePath:
+ description: directory to automatically save images in
+ type: string
+ autoSaveMinScanLines:
+ desciption: minimum number of scanlines (after cropping) for an image to be automatically saved
+ type: integer
+ rgbColor:
+ type: integer
+ title:
+ type: string
+ streamIndex:
+ description: MIMO channel. Not relevant when connected to SI (single Rx).
+ type: integer
+ useReverseAPI:
+ description: Synchronize with reverse API (1 for yes, 0 for no)
+ type: integer
+ reverseAPIAddress:
+ type: string
+ reverseAPIPort:
+ type: integer
+ reverseAPIDeviceIndex:
+ type: integer
+ reverseAPIChannelIndex:
+ type: integer
+
+APTDemodActions:
+ description: APTDemod
+ properties:
+ aos:
+ description: "Acquisition of signal"
+ type: object
+ properties:
+ satelliteName:
+ description: "Name of the satellite"
+ type: string
+ northToSouthPass:
+ description: "Satellite is passing from the North to the South (1) or South to North (0)"
+ type: integer
+ los:
+ description: "Loss of signal"
+ type: object
+ properties:
+ satelliteName:
+ description: "Name of the satellite"
+ type: string
diff --git a/swagger/sdrangel/api/swagger/include/ChannelActions.yaml b/swagger/sdrangel/api/swagger/include/ChannelActions.yaml
index 4b7b6e310..2b98fa72a 100644
--- a/swagger/sdrangel/api/swagger/include/ChannelActions.yaml
+++ b/swagger/sdrangel/api/swagger/include/ChannelActions.yaml
@@ -17,6 +17,8 @@ ChannelActions:
originatorChannelIndex:
description: Optional for reverse API. This is the channel index from where the message comes from.
type: integer
+ APTDemodActions:
+ $ref: "http://swgserver:8081/api/swagger/include/APTDemod.yaml#/APTDemodActions"
FileSinkActions:
$ref: "http://swgserver:8081/api/swagger/include/FileSink.yaml#/FileSinkActions"
FileSourceActions:
diff --git a/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml b/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml
index f72c19146..300ef351f 100644
--- a/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml
+++ b/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml
@@ -23,6 +23,8 @@ ChannelSettings:
$ref: "http://swgserver:8081/api/swagger/include/AMDemod.yaml#/AMDemodSettings"
AMModSettings:
$ref: "http://swgserver:8081/api/swagger/include/AMMod.yaml#/AMModSettings"
+ APTDemodSettings:
+ $ref: "http://swgserver:8081/api/swagger/include/APTDemod.yaml#/APTDemodSettings"
ATVDemodSettings:
$ref: "http://swgserver:8081/api/swagger/include/ATVDemod.yaml#/ATVDemodSettings"
ATVModSettings:
diff --git a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml
index 3f4d7805a..9cbaa9f35 100644
--- a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml
+++ b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml
@@ -25,6 +25,8 @@ FeatureSettings:
$ref: "http://swgserver:8081/api/swagger/include/Map.yaml#/MapSettings"
RigCtlServerSettings:
$ref: "http://swgserver:8081/api/swagger/include/RigCtlServer.yaml#/RigCtlServerSettings"
+ SatelliteTrackerSettings:
+ $ref: "http://swgserver:8081/api/swagger/include/SatelliteTracker.yaml#/SatelliteTrackerSettings"
StarTrackerSettings:
$ref: "http://swgserver:8081/api/swagger/include/StarTracker.yaml#/StarTrackerSettings"
SimplePTTSettings:
diff --git a/swagger/sdrangel/api/swagger/include/GS232Controller.yaml b/swagger/sdrangel/api/swagger/include/GS232Controller.yaml
index 3ffbbad48..347fa5239 100644
--- a/swagger/sdrangel/api/swagger/include/GS232Controller.yaml
+++ b/swagger/sdrangel/api/swagger/include/GS232Controller.yaml
@@ -25,6 +25,18 @@ GS232ControllerSettings:
elevationOffset:
description: Elevation offset in degrees
type: integer
+ azimuthMin:
+ description: Minimum azimuth the controller will output
+ type: integer
+ azimuthMax:
+ description: Maximum azimuth the controller will output
+ type: integer
+ elevationMin:
+ description: Minimum elevation the controller will output
+ type: integer
+ elevationMax:
+ description: Maximum elevation the controller will output
+ type: integer
title:
type: string
rgbColor:
diff --git a/swagger/sdrangel/api/swagger/include/Map.yaml b/swagger/sdrangel/api/swagger/include/Map.yaml
index 19ff43c16..a30ce9c7b 100644
--- a/swagger/sdrangel/api/swagger/include/Map.yaml
+++ b/swagger/sdrangel/api/swagger/include/Map.yaml
@@ -61,3 +61,27 @@ MapItem:
description: "Altitude / height above sea level in metres"
type: number
format: float
+ track:
+ description: "Track/path the item has taken"
+ type: array
+ items:
+ $ref: "http://swgserver:8081/api/swagger/include/Map.yaml#/MapCoordinate"
+ predictedTrack:
+ description: "Track/path the item is predicted to take"
+ type: array
+ items:
+ $ref: "http://swgserver:8081/api/swagger/include/Map.yaml#/MapCoordinate"
+
+MapCoordinate:
+ description: "A map coordinate"
+ properties:
+ latitude:
+ type: number
+ format: float
+ longitude:
+ type: number
+ format: float
+ altitude:
+ type: number
+ format: float
+
diff --git a/swagger/sdrangel/api/swagger/include/SatelliteTracker.yaml b/swagger/sdrangel/api/swagger/include/SatelliteTracker.yaml
new file mode 100644
index 000000000..6d7636b2d
--- /dev/null
+++ b/swagger/sdrangel/api/swagger/include/SatelliteTracker.yaml
@@ -0,0 +1,109 @@
+SatelliteTrackerSettings:
+ description: "Satellite Tracker settings"
+ properties:
+ latitude:
+ description: "Latitude in decimal degrees (North positive) of antenna location"
+ type: number
+ format: float
+ longitude:
+ description: "Longitude in decimal degrees (East positive) of antenna location"
+ type: number
+ format: float
+ heightAboveSeaLevel:
+ description: "Height above sea level in metres of antenna location"
+ type: number
+ format: float
+ target:
+ description: "Target satellite"
+ type: string
+ satellites:
+ description: "Satellites to track"
+ type: array
+ items:
+ type: string
+ tles:
+ description: "Two line element files"
+ type: array
+ items:
+ type: string
+ dateTime:
+ description: "Date and time of observation. ISO 8601 extended format: yyyy-MM-ddTHH:mm:ss with Z suffix for UTC. Empty string for current time."
+ type: string
+ minAOSElevation:
+ description: "Minimum elevation in degrees for AOS"
+ type: integer
+ minPassElevation:
+ description: "Minimum elevation in degrees for a pass"
+ type: integer
+ rotatorMaxAzimuth:
+ description: "Maximum azimuth in degrees for the rotator"
+ type: integer
+ rotatorMaxElevation:
+ description: "Maximum elevation in degrees for elevation"
+ type: integer
+ azElUnits:
+ description: "DMS (0) DM (1) D (2) Decimal (3)"
+ type: integer
+ groundTrackPoints:
+ description: "Number of points used to draw ground tracks"
+ type: integer
+ dateFormat:
+ desciption: "Format for dates in the GUI (E.g: yy/MM/dd)"
+ type: string
+ utc:
+ description: "Times are UTC (1) or local (0)"
+ type: integer
+ updatePeriod:
+ description: "Time in seconds between each calculation of the target's position"
+ type: number
+ format: float
+ dopplerPeriod:
+ description: "Time in seconds between each Doppler correction"
+ type: number
+ format: float
+ predictionPeriod:
+ description: "How many days ahead to predict passes in"
+ type: integer
+ passStartTime:
+ description: "Time after which a pass must start"
+ type: string
+ passFinishTime:
+ description: "Time before which a pass must finish"
+ type: string
+ defaultFrequency:
+ description: "Frequency to use for Doppler and free space path loss calculations in Satellite data table"
+ type: number
+ format: float
+ drawOnMap:
+ description: "Draw satellites on the Map (1 for yes, 0 for no)"
+ type: integer
+ autoTarget:
+ description: "Automatically select target on AOS (1 for yes, 0 for no)"
+ type: integer
+ aosSpeech:
+ description: "Speech warning on AOS"
+ type: string
+ losSpeech:
+ description: "Speech warning on LOS"
+ type: string
+ aosCommand:
+ description: "Command to execute on AOS for all satellites"
+ type: string
+ losCommand:
+ description: "Command to execute on LOS for all satellites"
+ type: string
+ title:
+ type: string
+ rgbColor:
+ type: integer
+ useReverseAPI:
+ description: Synchronize with reverse API (1 for yes, 0 for no)
+ type: integer
+ reverseAPIAddress:
+ type: string
+ reverseAPIPort:
+ type: integer
+ reverseAPIDeviceIndex:
+ type: integer
+ reverseAPIChannelIndex:
+ type: integer
diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html
index e7bd6038b..016942a69 100644
--- a/swagger/sdrangel/code/html2/index.html
+++ b/swagger/sdrangel/code/html2/index.html
@@ -1107,6 +1107,127 @@ margin-bottom: 20px;
}
},
"description" : "APRS settings"
+};
+ defs.APTDemodActions = {
+ "properties" : {
+ "aos" : {
+ "$ref" : "#/definitions/APTDemodActions_aos"
+ },
+ "los" : {
+ "$ref" : "#/definitions/APTDemodActions_los"
+ }
+ },
+ "description" : "APTDemod"
+};
+ defs.APTDemodActions_aos = {
+ "properties" : {
+ "satelliteName" : {
+ "type" : "string",
+ "description" : "Name of the satellite"
+ },
+ "northToSouthPass" : {
+ "type" : "integer",
+ "description" : "Satellite is passing from the North to the South (1) or South to North (0)"
+ }
+ },
+ "description" : "Acquisition of signal"
+};
+ defs.APTDemodActions_los = {
+ "properties" : {
+ "satelliteName" : {
+ "type" : "string",
+ "description" : "Name of the satellite"
+ }
+ },
+ "description" : "Loss of signal"
+};
+ defs.APTDemodSettings = {
+ "properties" : {
+ "inputFrequencyOffset" : {
+ "type" : "integer",
+ "format" : "int64",
+ "description" : "channel center frequency shift from baseband center in Hz"
+ },
+ "rfBandwidth" : {
+ "type" : "number",
+ "format" : "float",
+ "description" : "channel RF bandwidth in Hz"
+ },
+ "fmDeviation" : {
+ "type" : "integer",
+ "description" : "frequency deviation in Hz"
+ },
+ "cropNoise" : {
+ "type" : "integer",
+ "description" : "crop noise from top and bottom of image"
+ },
+ "denoise" : {
+ "type" : "integer",
+ "description" : "apply denoise filter to image"
+ },
+ "linearEqualise" : {
+ "type" : "integer",
+ "description" : "apply linear equalisation to image"
+ },
+ "histogramEqualise" : {
+ "type" : "integer",
+ "description" : "apply histogram equalisation to image"
+ },
+ "precipitationOverlay" : {
+ "type" : "integer",
+ "description" : "create colour overlay of precipitation"
+ },
+ "flip" : {
+ "type" : "integer",
+ "description" : "flip image for South to North passes"
+ },
+ "channels" : {
+ "type" : "integer",
+ "description" : "which channel to display (0=both, 1=A, 2=B)"
+ },
+ "decodeEnabled" : {
+ "type" : "integer",
+ "description" : "controls whether the decoder is enabled"
+ },
+ "autoSave" : {
+ "type" : "integer",
+ "description" : "automatically save images when acquisition is stopped"
+ },
+ "autoSavePath" : {
+ "type" : "string",
+ "description" : "directory to automatically save images in"
+ },
+ "autoSaveMinScanLines" : {
+ "type" : "integer"
+ },
+ "rgbColor" : {
+ "type" : "integer"
+ },
+ "title" : {
+ "type" : "string"
+ },
+ "streamIndex" : {
+ "type" : "integer",
+ "description" : "MIMO channel. Not relevant when connected to SI (single Rx)."
+ },
+ "useReverseAPI" : {
+ "type" : "integer",
+ "description" : "Synchronize with reverse API (1 for yes, 0 for no)"
+ },
+ "reverseAPIAddress" : {
+ "type" : "string"
+ },
+ "reverseAPIPort" : {
+ "type" : "integer"
+ },
+ "reverseAPIDeviceIndex" : {
+ "type" : "integer"
+ },
+ "reverseAPIChannelIndex" : {
+ "type" : "integer"
+ }
+ },
+ "description" : "APTDemod"
};
defs.ATVDemodSettings = {
"properties" : {
@@ -2411,6 +2532,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Optional for reverse API. This is the channel index from where the message comes from."
},
+ "APTDemodActions" : {
+ "$ref" : "#/definitions/APTDemodActions"
+ },
"FileSinkActions" : {
"$ref" : "#/definitions/FileSinkActions"
},
@@ -2659,6 +2783,9 @@ margin-bottom: 20px;
"AMModSettings" : {
"$ref" : "#/definitions/AMModSettings"
},
+ "APTDemodSettings" : {
+ "$ref" : "#/definitions/APTDemodSettings"
+ },
"ATVDemodSettings" : {
"$ref" : "#/definitions/ATVDemodSettings"
},
@@ -4188,6 +4315,9 @@ margin-bottom: 20px;
"RigCtlServerSettings" : {
"$ref" : "#/definitions/RigCtlServerSettings"
},
+ "SatelliteTrackerSettings" : {
+ "$ref" : "#/definitions/SatelliteTrackerSettings"
+ },
"StarTrackerSettings" : {
"$ref" : "#/definitions/StarTrackerSettings"
},
@@ -4946,6 +5076,22 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Elevation offset in degrees"
},
+ "azimuthMin" : {
+ "type" : "integer",
+ "description" : "Minimum azimuth the controller will output"
+ },
+ "azimuthMax" : {
+ "type" : "integer",
+ "description" : "Maximum azimuth the controller will output"
+ },
+ "elevationMin" : {
+ "type" : "integer",
+ "description" : "Minimum elevation the controller will output"
+ },
+ "elevationMax" : {
+ "type" : "integer",
+ "description" : "Maximum elevation the controller will output"
+ },
"title" : {
"type" : "string"
},
@@ -6266,6 +6412,23 @@ margin-bottom: 20px;
}
},
"description" : "Map"
+};
+ defs.MapCoordinate = {
+ "properties" : {
+ "latitude" : {
+ "type" : "number",
+ "format" : "float"
+ },
+ "longitude" : {
+ "type" : "number",
+ "format" : "float"
+ },
+ "altitude" : {
+ "type" : "number",
+ "format" : "float"
+ }
+ },
+ "description" : "A map coordinate"
};
defs.MapItem = {
"required" : [ "name" ],
@@ -6303,6 +6466,20 @@ margin-bottom: 20px;
"type" : "number",
"format" : "float",
"description" : "Altitude / height above sea level in metres"
+ },
+ "track" : {
+ "type" : "array",
+ "description" : "Track/path the item has taken",
+ "items" : {
+ "$ref" : "#/definitions/MapCoordinate"
+ }
+ },
+ "predictedTrack" : {
+ "type" : "array",
+ "description" : "Track/path the item is predicted to take",
+ "items" : {
+ "$ref" : "#/definitions/MapCoordinate"
+ }
}
},
"description" : "An item to draw on the map. Set image to an empty string to remove item from the map."
@@ -6343,6 +6520,20 @@ margin-bottom: 20px;
"type" : "number",
"format" : "float",
"description" : "Altitude / height above sea level in metres"
+ },
+ "track" : {
+ "type" : "array",
+ "description" : "Track/path the item has taken",
+ "items" : {
+ "$ref" : "#/definitions/MapCoordinate"
+ }
+ },
+ "predictedTrack" : {
+ "type" : "array",
+ "description" : "Track/path the item is predicted to take",
+ "items" : {
+ "$ref" : "#/definitions/MapCoordinate"
+ }
}
},
"description" : "An item to draw on the map. Set image to an empty string to remove item from the map."
@@ -8360,6 +8551,152 @@ margin-bottom: 20px;
}
},
"description" : "Information about a logical device available from an attached hardware device that can be used as a sampling device"
+};
+ defs.SatelliteTrackerSettings = {
+ "properties" : {
+ "latitude" : {
+ "type" : "number",
+ "format" : "float",
+ "description" : "Latitude in decimal degrees (North positive) of antenna location"
+ },
+ "longitude" : {
+ "type" : "number",
+ "format" : "float",
+ "description" : "Longitude in decimal degrees (East positive) of antenna location"
+ },
+ "heightAboveSeaLevel" : {
+ "type" : "number",
+ "format" : "float",
+ "description" : "Height above sea level in metres of antenna location"
+ },
+ "target" : {
+ "type" : "string",
+ "description" : "Target satellite"
+ },
+ "satellites" : {
+ "type" : "array",
+ "description" : "Satellites to track",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "tles" : {
+ "type" : "array",
+ "description" : "Two line element files",
+ "items" : {
+ "type" : "string"
+ }
+ },
+ "dateTime" : {
+ "type" : "string",
+ "description" : "Date and time of observation. ISO 8601 extended format: yyyy-MM-ddTHH:mm:ss with Z suffix for UTC. Empty string for current time."
+ },
+ "minAOSElevation" : {
+ "type" : "integer",
+ "description" : "Minimum elevation in degrees for AOS"
+ },
+ "minPassElevation" : {
+ "type" : "integer",
+ "description" : "Minimum elevation in degrees for a pass"
+ },
+ "rotatorMaxAzimuth" : {
+ "type" : "integer",
+ "description" : "Maximum azimuth in degrees for the rotator"
+ },
+ "rotatorMaxElevation" : {
+ "type" : "integer",
+ "description" : "Maximum elevation in degrees for elevation"
+ },
+ "azElUnits" : {
+ "type" : "integer",
+ "description" : "DMS (0) DM (1) D (2) Decimal (3)"
+ },
+ "groundTrackPoints" : {
+ "type" : "integer",
+ "description" : "Number of points used to draw ground tracks"
+ },
+ "dateFormat" : {
+ "type" : "string"
+ },
+ "utc" : {
+ "type" : "integer",
+ "description" : "Times are UTC (1) or local (0)"
+ },
+ "updatePeriod" : {
+ "type" : "number",
+ "format" : "float",
+ "description" : "Time in seconds between each calculation of the target's position"
+ },
+ "dopplerPeriod" : {
+ "type" : "number",
+ "format" : "float",
+ "description" : "Time in seconds between each Doppler correction"
+ },
+ "predictionPeriod" : {
+ "type" : "integer",
+ "description" : "How many days ahead to predict passes in"
+ },
+ "passStartTime" : {
+ "type" : "string",
+ "description" : "Time after which a pass must start"
+ },
+ "passFinishTime" : {
+ "type" : "string",
+ "description" : "Time before which a pass must finish"
+ },
+ "defaultFrequency" : {
+ "type" : "number",
+ "format" : "float",
+ "description" : "Frequency to use for Doppler and free space path loss calculations in Satellite data table"
+ },
+ "drawOnMap" : {
+ "type" : "integer",
+ "description" : "Draw satellites on the Map (1 for yes, 0 for no)"
+ },
+ "autoTarget" : {
+ "type" : "integer",
+ "description" : "Automatically select target on AOS (1 for yes, 0 for no)"
+ },
+ "aosSpeech" : {
+ "type" : "string",
+ "description" : "Speech warning on AOS"
+ },
+ "losSpeech" : {
+ "type" : "string",
+ "description" : "Speech warning on LOS"
+ },
+ "aosCommand" : {
+ "type" : "string",
+ "description" : "Command to execute on AOS for all satellites"
+ },
+ "losCommand" : {
+ "type" : "string",
+ "description" : "Command to execute on LOS for all satellites"
+ },
+ "title" : {
+ "type" : "string"
+ },
+ "rgbColor" : {
+ "type" : "integer"
+ },
+ "useReverseAPI" : {
+ "type" : "integer",
+ "description" : "Synchronize with reverse API (1 for yes, 0 for no)"
+ },
+ "reverseAPIAddress" : {
+ "type" : "string"
+ },
+ "reverseAPIPort" : {
+ "type" : "integer"
+ },
+ "reverseAPIDeviceIndex" : {
+ "type" : "integer"
+ },
+ "reverseAPIChannelIndex" : {
+ "type" : "integer"
+ }
+ },
+ "description" : "Satellite Tracker settings"
};
defs.SigMFFileInputActions = {
"properties" : {
@@ -45286,7 +45623,7 @@ except ApiException as e: