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.bmp airlinelogos/AAH.bmp airlinelogos/AAL.bmp + airlinelogos/AAQ.bmp airlinelogos/AAR.bmp + airlinelogos/AAV.bmp airlinelogos/AAW.bmp airlinelogos/AAY.bmp airlinelogos/AAZ.bmp + airlinelogos/AB.bmp airlinelogos/ABB.bmp airlinelogos/ABD.bmp airlinelogos/ABG.bmp @@ -24,8 +27,11 @@ airlinelogos/ACA.bmp airlinelogos/ACG.bmp airlinelogos/ACI.bmp + airlinelogos/ACL.bmp airlinelogos/ACV.bmp airlinelogos/ADN.bmp + airlinelogos/ADO.bmp + airlinelogos/ADR.bmp airlinelogos/ADY.bmp airlinelogos/AEA.bmp airlinelogos/AEE.bmp @@ -48,7 +54,13 @@ airlinelogos/AIC.bmp airlinelogos/AIE.bmp airlinelogos/AIH.bmp + airlinelogos/AIJ.bmp + airlinelogos/AIQ.bmp + airlinelogos/AIRBOREALIS.bmp airlinelogos/AIRCOSTA.bmp + airlinelogos/AIRFLAMENCO.bmp + airlinelogos/AIRJUAN.bmp + airlinelogos/AIRSEVEN.bmp airlinelogos/AIZ.bmp airlinelogos/AJA.bmp airlinelogos/AJB.bmp @@ -57,11 +69,18 @@ airlinelogos/AJK.bmp airlinelogos/AJT.bmp airlinelogos/AKC.bmp + airlinelogos/AKL.bmp + airlinelogos/AKS.bmp + airlinelogos/ALK.bmp + airlinelogos/ALN.bmp airlinelogos/ALV.bmp airlinelogos/ALW.bmp airlinelogos/ALX.bmp airlinelogos/ALY.bmp + airlinelogos/AMA.bmp airlinelogos/AMC.bmp + airlinelogos/AMF.bmp + airlinelogos/AMJ.bmp airlinelogos/AMU.bmp airlinelogos/AMV.bmp airlinelogos/AMX.bmp @@ -78,6 +97,8 @@ airlinelogos/ANT.bmp airlinelogos/ANZ.bmp airlinelogos/AOJ.bmp + airlinelogos/AOL.bmp + airlinelogos/APC.bmp airlinelogos/APF.bmp airlinelogos/APG.bmp airlinelogos/APJ.bmp @@ -89,12 +110,14 @@ airlinelogos/ARK.bmp airlinelogos/ARN.bmp airlinelogos/ARR.bmp + airlinelogos/ART.bmp airlinelogos/ARU.bmp airlinelogos/ARZ.bmp airlinelogos/ASA.bmp airlinelogos/ASB.bmp airlinelogos/ASH.bmp airlinelogos/ASL.bmp + airlinelogos/ASP.bmp airlinelogos/ASQ.bmp airlinelogos/ASV.bmp airlinelogos/ASY.bmp @@ -112,223 +135,579 @@ airlinelogos/AUS5.bmp airlinelogos/AUT.bmp airlinelogos/AVA.bmp + airlinelogos/AVIAIR.bmp airlinelogos/AVJ.bmp airlinelogos/AVN.bmp airlinelogos/AVV.bmp airlinelogos/AVW.bmp + airlinelogos/AWC.bmp airlinelogos/AWE.bmp airlinelogos/AWG.bmp + airlinelogos/AWH.bmp airlinelogos/AWI.bmp airlinelogos/AWK.bmp airlinelogos/AWM.bmp airlinelogos/AWT.bmp + airlinelogos/AXA.bmp airlinelogos/AXB.bmp airlinelogos/AXE.bmp + airlinelogos/AXG.bmp airlinelogos/AXK.bmp + airlinelogos/AXL.bmp airlinelogos/AXM.bmp airlinelogos/AXU.bmp airlinelogos/AYG.bmp airlinelogos/AYT.bmp airlinelogos/AZA.bmp + airlinelogos/AZD.bmp airlinelogos/AZG.bmp airlinelogos/AZI.bmp airlinelogos/AZM.bmp airlinelogos/AZN.bmp airlinelogos/AZO.bmp + airlinelogos/AZP.bmp airlinelogos/AZQ.bmp airlinelogos/AZU.bmp + airlinelogos/AZUf.bmp airlinelogos/AZV.bmp airlinelogos/AZW.bmp + airlinelogos/BAH.bmp + airlinelogos/BAV.bmp airlinelogos/BAW.bmp + airlinelogos/BAY.bmp airlinelogos/BBC.bmp airlinelogos/BBD.bmp airlinelogos/BBG.bmp airlinelogos/BCI.bmp airlinelogos/BCY.bmp airlinelogos/BDA.bmp + airlinelogos/BDF.bmp airlinelogos/BEE.bmp airlinelogos/BEL.bmp airlinelogos/BER.bmp + airlinelogos/BEY.bmp + airlinelogos/BEZ.bmp + airlinelogos/BFD.bmp + airlinelogos/BFL.bmp airlinelogos/BGA.bmp airlinelogos/BGH.bmp airlinelogos/BGL.bmp + airlinelogos/BGN.bmp airlinelogos/BGY.bmp airlinelogos/BHA.bmp + airlinelogos/BHL.bmp airlinelogos/BHP.bmp airlinelogos/BIE.bmp + airlinelogos/BJN.bmp + airlinelogos/BJO.bmp + airlinelogos/BKA.bmp + airlinelogos/BKP.bmp airlinelogos/BLF.bmp + airlinelogos/BLK.bmp airlinelogos/BLX.bmp + airlinelogos/BMA.bmp + airlinelogos/BML.bmp airlinelogos/BMR.bmp + airlinelogos/BNA.bmp + airlinelogos/BNL.bmp airlinelogos/BOE.bmp airlinelogos/BON.bmp airlinelogos/BOS.bmp airlinelogos/BOT.bmp airlinelogos/BOV.bmp airlinelogos/BOX.bmp + airlinelogos/BPA.bmp airlinelogos/BQB.bmp + airlinelogos/BRAVO.bmp + airlinelogos/BRH.bmp airlinelogos/BRINDABELLA.bmp airlinelogos/BRJ.bmp + airlinelogos/BRO.bmp airlinelogos/BRQ.bmp airlinelogos/BRU.bmp airlinelogos/BRXb.bmp airlinelogos/BSK.bmp airlinelogos/BTI.bmp + airlinelogos/BTK.bmp airlinelogos/BTN.bmp airlinelogos/BTQ.bmp + airlinelogos/BTV.bmp + airlinelogos/BTX.bmp airlinelogos/BUC.bmp airlinelogos/BUR.bmp + airlinelogos/BVI.bmp airlinelogos/BVR.bmp + airlinelogos/BWA.bmp + airlinelogos/BWJ.bmp airlinelogos/BXA.bmp + airlinelogos/BYA.bmp + airlinelogos/BYC.bmp airlinelogos/BYR.bmp + airlinelogos/BYS.bmp + airlinelogos/BZE.bmp airlinelogos/BZH.bmp + airlinelogos/CAA.bmp airlinelogos/CAD.bmp airlinelogos/CAI.bmp + airlinelogos/CAJ.bmp + airlinelogos/CAK.bmp + airlinelogos/CAL.bmp airlinelogos/CAO.bmp + airlinelogos/CAT.bmp airlinelogos/CAV.bmp + airlinelogos/CAW.bmp airlinelogos/CAY.bmp + airlinelogos/CAZ.bmp + airlinelogos/CBA.bmp + airlinelogos/CBG.bmp + airlinelogos/CBH.bmp + airlinelogos/CBI.bmp airlinelogos/CBJ.bmp + airlinelogos/CBM.bmp + airlinelogos/CBN.bmp + airlinelogos/CBX.bmp airlinelogos/CCA.bmp + airlinelogos/CCC.bmp airlinelogos/CCD.bmp airlinelogos/CCE.bmp airlinelogos/CCM.bmp + airlinelogos/CCS.bmp airlinelogos/CDA.bmp airlinelogos/CDC.bmp airlinelogos/CDG.bmp + airlinelogos/CDN.bmp + airlinelogos/CDO.bmp + airlinelogos/CDQ.bmp + airlinelogos/CDR.bmp + airlinelogos/CDX.bmp + airlinelogos/CDY.bmp airlinelogos/CEB.bmp + airlinelogos/CEG.bmp airlinelogos/CEL.bmp airlinelogos/CES.bmp airlinelogos/CEY.bmp + airlinelogos/CEZ.bmp airlinelogos/CFE.bmp + airlinelogos/CFF.bmp airlinelogos/CFG.bmp + airlinelogos/CFH.bmp + airlinelogos/CFL.bmp + airlinelogos/CFR.bmp + airlinelogos/CFS.bmp + airlinelogos/CFV.bmp + airlinelogos/CGE.bmp airlinelogos/CGF.bmp airlinelogos/CGH.bmp airlinelogos/CGN.bmp + airlinelogos/CGR.bmp + airlinelogos/CGZ.bmp airlinelogos/CHB.bmp airlinelogos/CHH.bmp + airlinelogos/CHI.bmp + airlinelogos/CHJ.bmp + airlinelogos/CHQ.bmp + airlinelogos/CHR.bmp + airlinelogos/CIA.bmp + airlinelogos/CIG.bmp + airlinelogos/CIL.bmp airlinelogos/CIM.bmp + airlinelogos/CIN.bmp + airlinelogos/CIT.bmp + airlinelogos/CIV.bmp airlinelogos/CJA.bmp airlinelogos/CJC.bmp + airlinelogos/CJE.bmp + airlinelogos/CJL.bmp + airlinelogos/CJM.bmp + airlinelogos/CJR.bmp airlinelogos/CJT.bmp + airlinelogos/CJX.bmp + airlinelogos/CJZ.bmp airlinelogos/CKK.bmp airlinelogos/CKS.bmp + airlinelogos/CLB.bmp + airlinelogos/CLD.bmp + airlinelogos/CLF.bmp airlinelogos/CLG.bmp + airlinelogos/CLH.bmp + airlinelogos/CLN.bmp + airlinelogos/CLO.bmp + airlinelogos/CLOUDGLOBAL.bmp + airlinelogos/CLP.bmp + airlinelogos/CLU.bmp airlinelogos/CLX.bmp + airlinelogos/CLY.bmp + airlinelogos/CMD.bmp + airlinelogos/CME.bmp airlinelogos/CMM.bmp + airlinelogos/CMP.bmp + airlinelogos/CNA.bmp airlinelogos/CND.bmp + airlinelogos/CNF.bmp airlinelogos/CNK.bmp + airlinelogos/CNP.bmp + airlinelogos/CNW.bmp + airlinelogos/COB.bmp + airlinelogos/COL.bmp airlinelogos/CON1.bmp + airlinelogos/CONa.bmp + airlinelogos/COO.bmp + airlinelogos/CORPORATEAIR.bmp airlinelogos/COT.bmp + airlinelogos/COW.bmp + airlinelogos/COY.bmp airlinelogos/CPA.bmp + airlinelogos/CPAC.bmp + airlinelogos/CPD.bmp + airlinelogos/CPE.bmp airlinelogos/CPN.bmp + airlinelogos/CPP.bmp + airlinelogos/CPS.bmp + airlinelogos/CPV.bmp airlinelogos/CPZ.bmp airlinelogos/CQH.bmp airlinelogos/CQN.bmp + airlinelogos/CR.bmp + airlinelogos/CRA.bmp airlinelogos/CRC.bmp + airlinelogos/CRF.bmp + airlinelogos/CRK.bmp airlinelogos/CRL.bmp airlinelogos/CRN.bmp + airlinelogos/CRNa.bmp airlinelogos/CRO.bmp airlinelogos/CRQ.bmp + airlinelogos/CRR.bmp airlinelogos/CRUZ.bmp airlinelogos/CSA.bmp + airlinelogos/CSB.bmp airlinelogos/CSC.bmp airlinelogos/CSH.bmp + airlinelogos/CSI.bmp airlinelogos/CSN.bmp + airlinelogos/CSQ.bmp airlinelogos/CSS.bmp + airlinelogos/CST.bmp + airlinelogos/CSV.bmp airlinelogos/CSZ.bmp + airlinelogos/CTB.bmp + airlinelogos/CTE.bmp + airlinelogos/CTF.bmp + airlinelogos/CTK.bmp airlinelogos/CTM.bmp airlinelogos/CTN.bmp + airlinelogos/CTV.bmp + airlinelogos/CTW.bmp airlinelogos/CUA.bmp airlinelogos/CUB.bmp + airlinelogos/CUH.bmp + airlinelogos/CUK.bmp + airlinelogos/CUL.bmp airlinelogos/CVA.bmp + airlinelogos/CVD.bmp + airlinelogos/CVE.bmp + airlinelogos/CVK.bmp + airlinelogos/CVR.bmp + airlinelogos/CVU.bmp + airlinelogos/CVZ.bmp + airlinelogos/CWA.bmp airlinelogos/CWC.bmp + airlinelogos/CWM.bmp + airlinelogos/CWY.bmp airlinelogos/CXA.bmp airlinelogos/CXB.bmp + airlinelogos/CXE.bmp + airlinelogos/CXF.bmp airlinelogos/CXH.bmp + airlinelogos/CXI.bmp + airlinelogos/CXM.bmp + airlinelogos/CXP.bmp + airlinelogos/CYF.bmp airlinelogos/CYL.bmp + airlinelogos/CYO.bmp airlinelogos/CYP.bmp + airlinelogos/CYT.bmp airlinelogos/CYZ.bmp + airlinelogos/DAB.bmp airlinelogos/DAC.bmp + airlinelogos/DAE.bmp + airlinelogos/DAF.bmp airlinelogos/DAH.bmp + airlinelogos/DAILY.bmp airlinelogos/DAL.bmp + airlinelogos/DAN.bmp airlinelogos/DAO.bmp airlinelogos/DAP.bmp + airlinelogos/DAR.bmp + airlinelogos/DAV.bmp + airlinelogos/DAZ.bmp + airlinelogos/DBC.bmp + airlinelogos/DCM.bmp airlinelogos/DCS.bmp + airlinelogos/DCT.bmp + airlinelogos/DCW.bmp + airlinelogos/DEJ.bmp airlinelogos/DER.bmp + airlinelogos/DET.bmp + airlinelogos/DFL.bmp + airlinelogos/DGX.bmp + airlinelogos/DHC.bmp + airlinelogos/DHE.bmp + airlinelogos/DHK.bmp airlinelogos/DHL.bmp + airlinelogos/DHR.bmp + airlinelogos/DHV.bmp airlinelogos/DHX.bmp + airlinelogos/DIG.bmp + airlinelogos/DIS.bmp + airlinelogos/DJC.bmp airlinelogos/DJT.bmp airlinelogos/DJU.bmp airlinelogos/DKH.bmp airlinelogos/DLA.bmp airlinelogos/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.bmp airlinelogos/DNV.bmp + airlinelogos/DNY.bmp airlinelogos/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.bmp airlinelogos/DQI.bmp airlinelogos/DRK.bmp + airlinelogos/DRM.bmp airlinelogos/DRU.bmp + airlinelogos/DRZ.bmp airlinelogos/DSM.bmp + airlinelogos/DSV.bmp airlinelogos/DTA.bmp airlinelogos/DTH.bmp + airlinelogos/DTO.bmp airlinelogos/DTR.bmp + airlinelogos/DVR.bmp + airlinelogos/DWG.bmp + airlinelogos/DWI.bmp airlinelogos/DYA.bmp + airlinelogos/DYM.bmp + airlinelogos/DYN.bmp + airlinelogos/DZR.bmp airlinelogos/EAA.bmp + airlinelogos/EAD.bmp + airlinelogos/EAF.bmp + airlinelogos/EAK.bmp airlinelogos/EAL.bmp + airlinelogos/EALOLD.bmp + airlinelogos/EAP.bmp airlinelogos/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.bmp airlinelogos/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.bmp airlinelogos/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.bmp airlinelogos/EKA.bmp + airlinelogos/EKY.bmp + airlinelogos/ELB.bmp + airlinelogos/ELE.bmp + airlinelogos/ELF.bmp + airlinelogos/ELH.bmp + airlinelogos/ELJ.bmp airlinelogos/ELL.bmp + airlinelogos/ELP.bmp + airlinelogos/ELT.bmp + airlinelogos/ELW.bmp + airlinelogos/ELY.bmp airlinelogos/EMB.bmp + airlinelogos/EML.bmp + airlinelogos/EMM.bmp + airlinelogos/EMT.bmp + airlinelogos/ENF.bmp airlinelogos/ENJ.bmp + airlinelogos/ENK.bmp airlinelogos/ENT.bmp + airlinelogos/ENW.bmp + airlinelogos/ENY.bmp + airlinelogos/EOA.bmp + airlinelogos/EOK.bmp airlinelogos/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.bmp airlinelogos/ERT.bmp + airlinelogos/ERY.bmp + airlinelogos/ESF.bmp + airlinelogos/ESJ.bmp airlinelogos/ESQ.bmp + airlinelogos/ESR.bmp + airlinelogos/EST.bmp + airlinelogos/ESW.bmp + airlinelogos/ETA.bmp airlinelogos/ETD.bmp airlinelogos/ETH.bmp + airlinelogos/ETI.bmp + airlinelogos/ETP.bmp + airlinelogos/ETR.bmp airlinelogos/ETS.bmp + airlinelogos/EUC.bmp airlinelogos/EUG.bmp + airlinelogos/EUL.bmp + airlinelogos/EUS.bmp + airlinelogos/EUW.bmp airlinelogos/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.bmp airlinelogos/EWG.bmp + airlinelogos/EWR.bmp + airlinelogos/EWS.bmp + airlinelogos/EXA.bmp + airlinelogos/EXC.bmp + airlinelogos/EXH.bmp + airlinelogos/EXN.bmp + airlinelogos/EXP.bmp airlinelogos/EXS.bmp + airlinelogos/EXSa.bmp + airlinelogos/EXU.bmp + airlinelogos/EXV.bmp + airlinelogos/EXY.bmp + airlinelogos/EXZ.bmp + airlinelogos/EYC.bmp airlinelogos/EYT.bmp airlinelogos/EZA.bmp + airlinelogos/EZB.bmp airlinelogos/EZD.bmp airlinelogos/EZE.bmp + airlinelogos/EZS.bmp airlinelogos/EZY.bmp airlinelogos/FAB.bmp + airlinelogos/FAD.bmp airlinelogos/FAG.bmp airlinelogos/FAH.bmp airlinelogos/FAT.bmp + airlinelogos/FBA.bmp + airlinelogos/FBB.bmp airlinelogos/FBD.bmp airlinelogos/FBR.bmp + airlinelogos/FBU.bmp + airlinelogos/FC.bmp airlinelogos/FCM.bmp + airlinelogos/FDA.bmp airlinelogos/FDB.bmp + airlinelogos/FDJ.bmp + airlinelogos/FDT.bmp airlinelogos/FDX.bmp + airlinelogos/FDY.bmp + airlinelogos/FEA.bmp + airlinelogos/FEG.bmp + airlinelogos/FEI.bmp + airlinelogos/FFL.bmp + airlinelogos/FFM.bmp airlinelogos/FFT.bmp airlinelogos/FFV.bmp + airlinelogos/FGW.bmp airlinelogos/FHY.bmp + airlinelogos/FIA.bmp airlinelogos/FIN.bmp airlinelogos/FJA.bmp airlinelogos/FJI.bmp + airlinelogos/FJR.bmp + airlinelogos/FJW.bmp airlinelogos/FLE.bmp + airlinelogos/FLEXIFLY.bmp airlinelogos/FLI.bmp + airlinelogos/FLO.bmp + airlinelogos/FLYPELICAN.bmp airlinelogos/FNA.bmp airlinelogos/FPK.bmp airlinelogos/FPO.bmp airlinelogos/FPY.bmp airlinelogos/FRF.bmp + airlinelogos/FRG.bmp + airlinelogos/FRH.bmp airlinelogos/FSK.bmp + airlinelogos/FSQ.bmp + airlinelogos/FSY.bmp + airlinelogos/FTH.bmp + airlinelogos/FTO.bmp airlinelogos/FTZ.bmp airlinelogos/FWI.bmp + airlinelogos/FXP.bmp + airlinelogos/FXX.bmp + airlinelogos/FYL.bmp airlinelogos/FZA.bmp airlinelogos/FZW.bmp airlinelogos/GAA.bmp airlinelogos/GAI.bmp + airlinelogos/GAJ.bmp + airlinelogos/GAL.bmp + airlinelogos/GBB.bmp airlinelogos/GBK.bmp airlinelogos/GBQ.bmp + airlinelogos/GCL.bmp airlinelogos/GCR.bmp + airlinelogos/GCT.bmp airlinelogos/GDC.bmp + airlinelogos/GDE.bmp airlinelogos/GEA.bmp airlinelogos/GEC.bmp airlinelogos/GEO.bmp @@ -336,15 +715,23 @@ airlinelogos/GFG.bmp airlinelogos/GGN.bmp airlinelogos/GIA.bmp + airlinelogos/GJE.bmp + airlinelogos/GJI.bmp + airlinelogos/GJM.bmp + airlinelogos/GJS.bmp + airlinelogos/GJT.bmp airlinelogos/GLG.bmp airlinelogos/GLJ.bmp airlinelogos/GLO.bmp airlinelogos/GLR.bmp airlinelogos/GMI.bmp airlinelogos/GMQ.bmp + airlinelogos/GMR.bmp airlinelogos/GOW.bmp airlinelogos/GRL.bmp + airlinelogos/GSW.bmp airlinelogos/GTI.bmp + airlinelogos/GTR.bmp airlinelogos/GTV.bmp airlinelogos/GUG.bmp airlinelogos/GUY.bmp @@ -355,47 +742,106 @@ airlinelogos/HBH.bmp airlinelogos/HCC.bmp airlinelogos/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.bmp airlinelogos/HLX.bmp + airlinelogos/HND.bmp + airlinelogos/HNW.bmp airlinelogos/HOP.bmp + airlinelogos/HRT.bmp airlinelogos/HRV.bmp + airlinelogos/HTS.bmp + airlinelogos/HTU.bmp airlinelogos/HUN.bmp airlinelogos/HVN.bmp airlinelogos/HVY.bmp + airlinelogos/HWA.bmp airlinelogos/HXA.bmp + airlinelogos/HYA.bmp + airlinelogos/HYP.bmp + airlinelogos/HYT.bmp + airlinelogos/HZS.bmp airlinelogos/IAD.bmp + airlinelogos/IAE.bmp airlinelogos/IAW.bmp + airlinelogos/IAX.bmp airlinelogos/IBB.bmp airlinelogos/IBE.bmp airlinelogos/IBS.bmp + airlinelogos/IBX.bmp airlinelogos/ICE.bmp + airlinelogos/ICL.bmp + airlinelogos/ICV.bmp airlinelogos/IFC.bmp + airlinelogos/IFL.bmp airlinelogos/IGA.bmp airlinelogos/IGO.bmp + airlinelogos/IHO.bmp + airlinelogos/IIA.bmp airlinelogos/IJM.bmp - airlinelogos/Inter Island Air.bmp + airlinelogos/IKA.bmp + airlinelogos/IMX.bmp + airlinelogos/IOS.bmp airlinelogos/IRA.bmp + airlinelogos/IRB.bmp airlinelogos/IRC.bmp airlinelogos/IRK.bmp airlinelogos/IRM.bmp airlinelogos/ISK.bmp + airlinelogos/ISR.bmp airlinelogos/ISS.bmp airlinelogos/ISV.bmp + airlinelogos/IWY.bmp + airlinelogos/IXR.bmp + airlinelogos/IYA.bmp airlinelogos/IYE.bmp + airlinelogos/IZA.bmp + airlinelogos/IZG.bmp airlinelogos/JAF.bmp airlinelogos/JAI.bmp + airlinelogos/JAL.bmp + airlinelogos/JAS.bmp airlinelogos/JAT.bmp airlinelogos/JATnew.bmp airlinelogos/JAV.bmp + airlinelogos/JBE.bmp airlinelogos/JBU.bmp airlinelogos/JCC.bmp + airlinelogos/JCL.bmp + airlinelogos/JCM.bmp + airlinelogos/JEI.bmp + airlinelogos/JES.bmp airlinelogos/JET.bmp + airlinelogos/JFL.bmp airlinelogos/JG.bmp + airlinelogos/JIA.bmp + airlinelogos/JJA.bmp + airlinelogos/JJP.bmp + airlinelogos/JKR.bmp + airlinelogos/JLF.bmp airlinelogos/JLL.bmp + airlinelogos/JMA.bmp + airlinelogos/JME.bmp + airlinelogos/JML.bmp airlinelogos/JNA.bmp + airlinelogos/JNL.bmp + airlinelogos/JON.bmp airlinelogos/JOR.bmp airlinelogos/JOY.bmp + airlinelogos/JRC.bmp + airlinelogos/JRT.bmp airlinelogos/JSA.bmp airlinelogos/JST.bmp + airlinelogos/JSY.bmp + airlinelogos/JTA.bmp airlinelogos/JTF.bmp airlinelogos/JTG.bmp airlinelogos/JUS.bmp @@ -406,16 +852,31 @@ airlinelogos/KAB.bmp airlinelogos/KAC.bmp airlinelogos/KAL.bmp + airlinelogos/KAP.bmp + airlinelogos/KAR.bmp + airlinelogos/KAZ.bmp + airlinelogos/KBZ.bmp + airlinelogos/KDS.bmp + airlinelogos/KEM.bmp + airlinelogos/KEN.bmp airlinelogos/KFA.bmp + airlinelogos/KFE.bmp airlinelogos/KGL.bmp airlinelogos/KGO.bmp + airlinelogos/KGS.bmp airlinelogos/KHH.bmp airlinelogos/KHV.bmp + airlinelogos/KII.bmp airlinelogos/KIL.bmp + airlinelogos/KIS.bmp airlinelogos/KKK.bmp airlinelogos/KLC.bmp + airlinelogos/KLJ.bmp airlinelogos/KLM.bmp + airlinelogos/KME.bmp airlinelogos/KMF.bmp + airlinelogos/KMI.bmp + airlinelogos/KMK.bmp airlinelogos/KN.bmp airlinelogos/KNA.bmp airlinelogos/KNE.bmp @@ -424,24 +885,50 @@ airlinelogos/KRE.bmp airlinelogos/KRN.bmp airlinelogos/KRP.bmp + airlinelogos/KSZ.bmp + airlinelogos/KTB.bmp + airlinelogos/KYE.bmp airlinelogos/KZR.bmp + airlinelogos/KZU.bmp airlinelogos/LAA.bmp + airlinelogos/LAE.bmp + airlinelogos/LAK.bmp airlinelogos/LAL.bmp + airlinelogos/LAM.bmp airlinelogos/LAN.bmp + airlinelogos/LAO.bmp + airlinelogos/LAU.bmp airlinelogos/LAV.bmp airlinelogos/LBN.bmp + airlinelogos/LBQ.bmp airlinelogos/LBR.bmp + airlinelogos/LBT.bmp airlinelogos/LBY.bmp airlinelogos/LC.bmp airlinelogos/LCO.bmp + airlinelogos/LDC.bmp + airlinelogos/LDX.bmp airlinelogos/LER.bmp + airlinelogos/LEX.bmp airlinelogos/LFO.bmp + airlinelogos/LGF.bmp airlinelogos/LGL.bmp + airlinelogos/LGT.bmp + airlinelogos/LHA.bmp airlinelogos/LIA.bmp + airlinelogos/LIP.bmp + airlinelogos/LJC.bmp + airlinelogos/LJY.bmp airlinelogos/LKA.bmp airlinelogos/LKE.bmp + airlinelogos/LKF.bmp + airlinelogos/LKN.bmp + airlinelogos/LLK.bmp + airlinelogos/LLL.bmp + airlinelogos/LLM.bmp airlinelogos/LLP.bmp airlinelogos/LLR.bmp + airlinelogos/LMD.bmp airlinelogos/LMU.bmp airlinelogos/LNI.bmp airlinelogos/LNK.bmp @@ -450,80 +937,163 @@ airlinelogos/LPA.bmp airlinelogos/LPV.bmp airlinelogos/LRC.bmp + airlinelogos/LRS.bmp + airlinelogos/LSO.bmp + airlinelogos/LTC.bmp + airlinelogos/LTR.bmp airlinelogos/LUR.bmp airlinelogos/LVR.bmp + airlinelogos/LVT.bmp + airlinelogos/LWA.bmp + airlinelogos/LXG.bmp + airlinelogos/LXJ.bmp airlinelogos/LYM.bmp airlinelogos/LZB.bmp airlinelogos/MAC.bmp + airlinelogos/MAI.bmp airlinelogos/MAL.bmp airlinelogos/MAR.bmp airlinelogos/MAS.bmp airlinelogos/MAU.bmp + airlinelogos/MAV.bmp + airlinelogos/MAX.bmp + airlinelogos/MAY.bmp + airlinelogos/MBA.bmp + airlinelogos/MCM.bmp + airlinelogos/MDA.bmp airlinelogos/MDG.bmp airlinelogos/MEA.bmp + airlinelogos/MFG.bmp + airlinelogos/MGE.bmp + airlinelogos/MGL.bmp + airlinelogos/MGP.bmp airlinelogos/MGX.bmp + airlinelogos/MHO.bmp airlinelogos/MHS.bmp + airlinelogos/MHV.bmp airlinelogos/MJF.bmp airlinelogos/MKG.bmp + airlinelogos/MKR.bmp airlinelogos/MLD.bmp airlinelogos/MLH.bmp + airlinelogos/MLN.bmp airlinelogos/MLO.bmp airlinelogos/MLT.bmp airlinelogos/MMA.bmp airlinelogos/MMD.bmp + airlinelogos/MML.bmp + airlinelogos/MMN.bmp airlinelogos/MMZ.bmp airlinelogos/MNB.bmp + airlinelogos/MNG.bmp airlinelogos/MNO.bmp + airlinelogos/MNU.bmp airlinelogos/MON.bmp airlinelogos/MPA.bmp airlinelogos/MPE.bmp airlinelogos/MPH.bmp + airlinelogos/MPK.bmp + airlinelogos/MSA.bmp airlinelogos/MSC.bmp airlinelogos/MSE.bmp airlinelogos/MSF.bmp + airlinelogos/MSI.bmp + airlinelogos/MSJ.bmp airlinelogos/MSR.bmp airlinelogos/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.bmp airlinelogos/MYP.bmp + airlinelogos/MYW.bmp airlinelogos/MZN.bmp + airlinelogos/NAA.bmp airlinelogos/NAC.bmp airlinelogos/NAX.bmp airlinelogos/NCB.bmp + airlinelogos/NCR.bmp + airlinelogos/NFA.bmp airlinelogos/NGB.bmp airlinelogos/NGT.bmp + airlinelogos/NHX.bmp airlinelogos/NIA.bmp + airlinelogos/NIG.bmp + airlinelogos/NIH.bmp + airlinelogos/NIN.bmp + airlinelogos/NIS.bmp + airlinelogos/NJE.bmp airlinelogos/NKS.bmp + airlinelogos/NKT.bmp + airlinelogos/NLA.bmp airlinelogos/NLU.bmp airlinelogos/NLY.bmp airlinelogos/NMA.bmp airlinelogos/NMB.bmp + airlinelogos/NMG.bmp airlinelogos/NOK.bmp airlinelogos/NOS.bmp airlinelogos/NPT.bmp airlinelogos/NRL.bmp + airlinelogos/NRS.bmp airlinelogos/NSE.bmp + airlinelogos/NSJ.bmp + airlinelogos/NSW.bmp + airlinelogos/NTB.bmp + airlinelogos/NTF.bmp + airlinelogos/NUM.bmp airlinelogos/NVC.bmp airlinelogos/NVD.bmp airlinelogos/NVR.bmp + airlinelogos/NWG.bmp + airlinelogos/NWL.bmp airlinelogos/NWS.bmp + airlinelogos/NYS.bmp + airlinelogos/NYT.bmp + airlinelogos/NYX.bmp airlinelogos/OAE.bmp airlinelogos/OAL.bmp + airlinelogos/OAW.bmp airlinelogos/OBS.bmp airlinelogos/OCA.bmp + airlinelogos/OCL.bmp + airlinelogos/OES.bmp airlinelogos/OHY.bmp + airlinelogos/OIX.bmp airlinelogos/OKA.bmp + airlinelogos/OKC.bmp airlinelogos/OKS.bmp airlinelogos/OLC.bmp + airlinelogos/OLS.bmp airlinelogos/OMA.bmp + airlinelogos/OMS.bmp + airlinelogos/OMT.bmp airlinelogos/ONE.bmp airlinelogos/ONX.bmp airlinelogos/OPJ.bmp airlinelogos/ORB.bmp + airlinelogos/ORN.bmp airlinelogos/OTC.bmp + airlinelogos/OTF.bmp airlinelogos/OVA.bmp + airlinelogos/OWT.bmp + airlinelogos/OXM.bmp airlinelogos/OZW.bmp + airlinelogos/PAC.bmp + airlinelogos/PACIFIC.bmp airlinelogos/PAG.bmp + airlinelogos/PAJ.bmp airlinelogos/PAL.bmp airlinelogos/PAM.bmp + airlinelogos/PAO.bmp + airlinelogos/PAPILLON.bmp + airlinelogos/PAV.bmp + airlinelogos/PBD.bmp + airlinelogos/PCO.bmp airlinelogos/PCP.bmp airlinelogos/PER.bmp airlinelogos/PEV.bmp @@ -531,13 +1101,21 @@ airlinelogos/PFZ.bmp airlinelogos/PGA.bmp airlinelogos/PGT.bmp + airlinelogos/PHU.bmp airlinelogos/PIA.bmp airlinelogos/PIC.bmp + airlinelogos/PICa.bmp + airlinelogos/PICb.bmp + airlinelogos/PJC.bmp + airlinelogos/PJS.bmp airlinelogos/PKZ.bmp + airlinelogos/PLANET9.bmp airlinelogos/PLM.bmp airlinelogos/PLV.bmp airlinelogos/PLY.bmp airlinelogos/PMT.bmp + airlinelogos/PNC.bmp + airlinelogos/PNX.bmp airlinelogos/POE.bmp airlinelogos/POT.bmp airlinelogos/PRF.bmp @@ -546,167 +1124,310 @@ airlinelogos/PSC.bmp airlinelogos/PST.bmp airlinelogos/PTB.bmp + airlinelogos/PTH.bmp airlinelogos/PTR.bmp + airlinelogos/PUA.bmp + airlinelogos/PUE.bmp + airlinelogos/PUN.bmp + airlinelogos/PVD.bmp airlinelogos/PVN.bmp + airlinelogos/PVO.bmp + airlinelogos/PVV.bmp airlinelogos/PWD.bmp + airlinelogos/PXG.bmp airlinelogos/QAJ.bmp + airlinelogos/QAZ.bmp + airlinelogos/QBA.bmp airlinelogos/QDA.bmp airlinelogos/QFA.bmp airlinelogos/QLK.bmp + airlinelogos/QSM.bmp airlinelogos/QTR.bmp + airlinelogos/QXE.bmp + airlinelogos/RAC.bmp airlinelogos/RAE.bmp airlinelogos/RAM.bmp airlinelogos/RAR.bmp airlinelogos/RBA.bmp + airlinelogos/RBB.bmp airlinelogos/RBG.bmp + airlinelogos/RDS.bmp airlinelogos/REU.bmp airlinelogos/RGE.bmp airlinelogos/RJA.bmp airlinelogos/RJD.bmp airlinelogos/RKM.bmp + airlinelogos/RKS.bmp airlinelogos/RLA.bmp airlinelogos/RLH.bmp airlinelogos/RLK.bmp airlinelogos/RLU.bmp airlinelogos/RLX.bmp + airlinelogos/RLY.bmp + airlinelogos/RMY.bmp + airlinelogos/RNA.bmp airlinelogos/RNV.bmp airlinelogos/ROI.bmp + airlinelogos/ROJ.bmp airlinelogos/ROT.bmp airlinelogos/ROU.bmp + airlinelogos/RPA.bmp airlinelogos/RPB.bmp + airlinelogos/RPM.bmp + airlinelogos/RSI.bmp airlinelogos/RSY.bmp + airlinelogos/RTL.bmp airlinelogos/RUC.bmp + airlinelogos/RUK.bmp + airlinelogos/RUN.bmp + airlinelogos/RVP.bmp + airlinelogos/RWD.bmp airlinelogos/RWG.bmp airlinelogos/RWZ.bmp airlinelogos/RXA.bmp + airlinelogos/RYL.bmp airlinelogos/RYR.bmp airlinelogos/RYW.bmp airlinelogos/RZO.bmp + airlinelogos/SAA.bmp airlinelogos/SAI.bmp + airlinelogos/SAR.bmp airlinelogos/SAS.bmp + airlinelogos/SAW.bmp + airlinelogos/SAY.bmp + airlinelogos/SBB.bmp + airlinelogos/SBI.bmp + airlinelogos/SBL.bmp airlinelogos/SBM.bmp + airlinelogos/SBS.bmp + airlinelogos/SBU.bmp + airlinelogos/SCN.bmp airlinelogos/SCO.bmp airlinelogos/SCX.bmp + airlinelogos/SDA.bmp + airlinelogos/SDG.bmp airlinelogos/SDM.bmp + airlinelogos/SDU.bmp + airlinelogos/SEH.bmp airlinelogos/SEJ.bmp + airlinelogos/SEP.bmp + airlinelogos/SET.bmp airlinelogos/SEY.bmp airlinelogos/SFF.bmp + airlinelogos/SFJ.bmp + airlinelogos/SFR.bmp + airlinelogos/SFS.bmp airlinelogos/SFW.bmp airlinelogos/SGA.bmp + airlinelogos/SGB.bmp airlinelogos/SGG.bmp + airlinelogos/SGQ.bmp + airlinelogos/SHH.bmp + airlinelogos/SHI.bmp airlinelogos/SHU.bmp airlinelogos/SIA.bmp airlinelogos/SID.bmp airlinelogos/SIF.bmp + airlinelogos/SIL.bmp airlinelogos/SIN.bmp + airlinelogos/SIS.bmp + airlinelogos/SIY.bmp + airlinelogos/SJJ.bmp airlinelogos/SJO.bmp + airlinelogos/SJX.bmp + airlinelogos/SJY.bmp + airlinelogos/SKIPPERS.bmp airlinelogos/SKK.bmp airlinelogos/SKP.bmp airlinelogos/SKU.bmp airlinelogos/SKV.bmp + airlinelogos/SKW.bmp + airlinelogos/SKX.bmp + airlinelogos/SKY.bmp + airlinelogos/SKYDIVESTRATH.bmp + airlinelogos/SKYDIVESTRATHa.bmp airlinelogos/SKZ.bmp airlinelogos/SLI.bmp airlinelogos/SLK.bmp airlinelogos/SLM.bmp + airlinelogos/SLQ.bmp airlinelogos/SLX.bmp airlinelogos/SME.bmp airlinelogos/SMJ.bmp airlinelogos/SMR.bmp + airlinelogos/SNA.bmp + airlinelogos/SNG.bmp + airlinelogos/SNJ.bmp + airlinelogos/SOL.bmp + airlinelogos/SONOCO.bmp + airlinelogos/SOO.bmp airlinelogos/SOR.bmp airlinelogos/SOV.bmp + airlinelogos/SOW.bmp + airlinelogos/SPD.bmp airlinelogos/SPR.bmp airlinelogos/SQC.bmp + airlinelogos/SQH.bmp + airlinelogos/SQP.bmp airlinelogos/SQS.bmp + airlinelogos/SRC.bmp + airlinelogos/SRN.bmp + airlinelogos/SRQ.bmp airlinelogos/SRR.bmp + airlinelogos/SSF.bmp airlinelogos/SSQ.bmp airlinelogos/SSV.bmp + airlinelogos/SSX.bmp + airlinelogos/STP.bmp + airlinelogos/STRAT.bmp + airlinelogos/SUD.bmp airlinelogos/SUS.bmp airlinelogos/SVA.bmp airlinelogos/SVR.bmp + airlinelogos/SVW.bmp airlinelogos/SWA.bmp airlinelogos/SWAnew.bmp airlinelogos/SWG.bmp airlinelogos/SWM.bmp + airlinelogos/SWQ.bmp airlinelogos/SWR.bmp airlinelogos/SWT.bmp + airlinelogos/SXN.bmp airlinelogos/SXS.bmp + airlinelogos/SYG.bmp airlinelogos/SYL.bmp + airlinelogos/SZN.bmp + airlinelogos/TAG.bmp airlinelogos/TAI.bmp airlinelogos/TAK.bmp airlinelogos/TAM.bmp + airlinelogos/TAN.bmp airlinelogos/TAO.bmp airlinelogos/TAP.bmp + airlinelogos/TAPexp.bmp airlinelogos/TAR.bmp airlinelogos/TAY.bmp airlinelogos/TBA.bmp + airlinelogos/TBM.bmp airlinelogos/TBN.bmp airlinelogos/TBZ.bmp + airlinelogos/TCB.bmp airlinelogos/TCV.bmp airlinelogos/TCW.bmp airlinelogos/TCX.bmp airlinelogos/TDR.bmp + airlinelogos/TEK.bmp + airlinelogos/TEU.bmp + airlinelogos/TFF.bmp airlinelogos/TFL.bmp + airlinelogos/TGG.bmp + airlinelogos/TGN.bmp airlinelogos/TGW.bmp airlinelogos/TGZ.bmp airlinelogos/THA.bmp + airlinelogos/THD.bmp airlinelogos/THE.bmp airlinelogos/THT.bmp airlinelogos/THY.bmp airlinelogos/THYANA.bmp airlinelogos/TIA.bmp + airlinelogos/TIS.bmp + airlinelogos/TIV.bmp airlinelogos/TIW.bmp + airlinelogos/TJB.bmp + airlinelogos/TJJ.bmp airlinelogos/TJK.bmp airlinelogos/TJS.bmp + airlinelogos/TJT.bmp + airlinelogos/TKK.bmp + airlinelogos/TLM.bmp airlinelogos/TMA.bmp + airlinelogos/TMG.bmp airlinelogos/TMN.bmp airlinelogos/TMW.bmp airlinelogos/TNA.bmp airlinelogos/TNO.bmp + airlinelogos/TNU.bmp + airlinelogos/TNX.bmp + airlinelogos/TOK.bmp airlinelogos/TOM.bmp + airlinelogos/TOR.bmp airlinelogos/TPA.bmp airlinelogos/TPC.bmp airlinelogos/TPU.bmp airlinelogos/TRA.bmp + airlinelogos/TRJ.bmp airlinelogos/TSC.bmp airlinelogos/TSG.bmp airlinelogos/TSH.bmp airlinelogos/TSO.bmp airlinelogos/TSY.bmp + airlinelogos/TTE.bmp + airlinelogos/TTI.bmp airlinelogos/TTL.bmp + airlinelogos/TTW.bmp airlinelogos/TUA.bmp airlinelogos/TUI.bmp + airlinelogos/TUP.bmp airlinelogos/TUS.bmp airlinelogos/TUY.bmp airlinelogos/TVF.bmp + airlinelogos/TVJ.bmp airlinelogos/TVP.bmp airlinelogos/TVQ.bmp + airlinelogos/TVR.bmp airlinelogos/TVS.bmp + airlinelogos/TVV.bmp + airlinelogos/TWB.bmp airlinelogos/TWI.bmp + airlinelogos/TWY.bmp + airlinelogos/TYA.bmp airlinelogos/UAE.bmp airlinelogos/UAL.bmp + airlinelogos/UBA.bmp airlinelogos/UBD.bmp + airlinelogos/UBG.bmp airlinelogos/UCA.bmp + airlinelogos/UDN.bmp airlinelogos/UEA.bmp + airlinelogos/UFC.bmp + airlinelogos/UGD.bmp + airlinelogos/UIA.bmp + airlinelogos/UJC.bmp airlinelogos/UJX.bmp + airlinelogos/UKM.bmp + airlinelogos/ULC.bmp airlinelogos/ULG.bmp + airlinelogos/UNA.bmp airlinelogos/UPS.bmp airlinelogos/URG.bmp airlinelogos/URS.bmp + airlinelogos/USC.bmp airlinelogos/UTA.bmp airlinelogos/UTN.bmp airlinelogos/UTP.bmp airlinelogos/UTY.bmp + airlinelogos/UVT.bmp + airlinelogos/UWJ.bmp airlinelogos/UZB.bmp + airlinelogos/VAA.bmp + airlinelogos/VAJ.bmp airlinelogos/VAL.bmp airlinelogos/VAR.bmp airlinelogos/VAS.bmp airlinelogos/VAU.bmp airlinelogos/VAV.bmp + airlinelogos/VBA.bmp airlinelogos/VBB.bmp airlinelogos/VBW.bmp + airlinelogos/VCJ.bmp airlinelogos/VCV.bmp airlinelogos/VDA.bmp + airlinelogos/VDR.bmp + airlinelogos/VEC.bmp airlinelogos/VEL.bmp + airlinelogos/VES.bmp + airlinelogos/VET.bmp airlinelogos/VFC.bmp airlinelogos/VIL.bmp airlinelogos/VIM.bmp @@ -715,44 +1436,79 @@ airlinelogos/VIV.bmp airlinelogos/VJC.bmp airlinelogos/VJS.bmp + airlinelogos/VJT.bmp airlinelogos/VKG.bmp + airlinelogos/VKGOLD.bmp airlinelogos/VLG.bmp + airlinelogos/VLJ.bmp airlinelogos/VLK.bmp airlinelogos/VLM.bmp airlinelogos/VMP.bmp airlinelogos/VNE.bmp airlinelogos/VNL.bmp + airlinelogos/VOC.bmp airlinelogos/VOE.bmp + airlinelogos/VOI.bmp airlinelogos/VOZ.bmp airlinelogos/VPA.bmp + airlinelogos/VPC.bmp + airlinelogos/VPE.bmp airlinelogos/VRD.bmp airlinelogos/VRE.bmp airlinelogos/VRG.bmp airlinelogos/VSV.bmp airlinelogos/VTA.bmp + airlinelogos/VTE.bmp airlinelogos/VTI.bmp airlinelogos/VTM.bmp + airlinelogos/VTS.bmp + airlinelogos/VTU.bmp airlinelogos/VUN.bmp airlinelogos/VVC.bmp + airlinelogos/VVV.bmp + airlinelogos/WAA.bmp airlinelogos/WAJ.bmp + airlinelogos/WAL.bmp + airlinelogos/WAU.bmp airlinelogos/WDA.bmp + airlinelogos/WDE.bmp airlinelogos/WEN.bmp airlinelogos/WEW.bmp airlinelogos/WFR.bmp + airlinelogos/WGN.bmp + airlinelogos/WHS.bmp + airlinelogos/WIA.bmp airlinelogos/WIF.bmp + airlinelogos/WIL.bmp airlinelogos/WJA.bmp + airlinelogos/WLB.bmp airlinelogos/WLC.bmp + airlinelogos/WMN.bmp + airlinelogos/WON.bmp + airlinelogos/WORLD2FLY.bmp airlinelogos/WOW.bmp airlinelogos/WRC.bmp airlinelogos/WSG.bmp + airlinelogos/WSN.bmp + airlinelogos/WSW.bmp airlinelogos/WUK.bmp + airlinelogos/WWI.bmp airlinelogos/WWW.bmp airlinelogos/WZZ.bmp airlinelogos/XAH.bmp + airlinelogos/XAI.bmp + airlinelogos/XAU.bmp airlinelogos/XAX.bmp airlinelogos/XLF.bmp + airlinelogos/XLK.bmp airlinelogos/XLR.bmp airlinelogos/XME.bmp + airlinelogos/XOJ.bmp + airlinelogos/XRC.bmp + airlinelogos/XRO.bmp + airlinelogos/YEL.bmp airlinelogos/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. + +![APT Demodulator plugin GUI](../../../doc/img/APTDemod_plugin.png) + +* NOAA 15 transmits on 137.620 MHz. +* NOAA 18 transmits on 137.912 MHz. +* NOAA 19 transmits on 137.100 MHz. + +

Interface

+ +![APT Demodulator plugin GUI](../../../doc/img/APTDemod_plugin_settings.png) + +

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. + +![APT Demodulator settings dialog](../../../doc/img/APTDemod_plugin_settingsdialog.png) + +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 @@ 0 0 - 320 - 175 + 350 + 223 @@ -42,8 +42,8 @@ 10 10 - 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 @@ baudRate azimuthOffset elevationOffset + 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. +

API

Full details of the API can be found in the Swagger documentation. Here is a quick example of how to set the azimuth and elevation from the command line: diff --git a/plugins/feature/map/CMakeLists.txt b/plugins/feature/map/CMakeLists.txt index 4c1ea9dae..21528646a 100644 --- a/plugins/feature/map/CMakeLists.txt +++ b/plugins/feature/map/CMakeLists.txt @@ -34,6 +34,7 @@ if(NOT SERVER_MODE) mapbeacondialog.cpp mapbeacondialog.ui map.qrc + icons.qrc ) set(map_HEADERS ${map_HEADERS} diff --git a/plugins/feature/map/beacon.h b/plugins/feature/map/beacon.h index f4a5be696..8fb430dfe 100644 --- a/plugins/feature/map/beacon.h +++ b/plugins/feature/map/beacon.h @@ -74,6 +74,16 @@ struct Beacon { return QString("%1 kHz").arg(m_frequency/1000.0, 0, ',', 3); } + QString getFrequencyShortText() + { + if (m_frequency > 1000000000) + return QString("%1G").arg(m_frequency/1000000000.0, 0, ',', 1); + else if (m_frequency > 1000000) + return QString("%1M").arg(std::floor(m_frequency/1000000.0), 0, ',', 0); + else + return QString("%1k").arg(std::floor(m_frequency/1000.0), 0, ',', 0); + } + // Uses ; rather than , static QList *readIARUCSV(const QString &filename) { diff --git a/plugins/feature/map/icons.qrc b/plugins/feature/map/icons.qrc new file mode 100644 index 000000000..f462b389c --- /dev/null +++ b/plugins/feature/map/icons.qrc @@ -0,0 +1,5 @@ + + + icons/groundtracks.png + + diff --git a/plugins/feature/map/icons/groundtracks.png b/plugins/feature/map/icons/groundtracks.png new file mode 100644 index 000000000..e75c45a8c Binary files /dev/null and b/plugins/feature/map/icons/groundtracks.png differ diff --git a/plugins/feature/map/map.qrc b/plugins/feature/map/map.qrc index 93f43c7db..0310f0732 100644 --- a/plugins/feature/map/map.qrc +++ b/plugins/feature/map/map.qrc @@ -1,6 +1,7 @@ map/map.qml + map/map_5_12.qml map/antenna.png diff --git a/plugins/feature/map/map/map.qml b/plugins/feature/map/map/map.qml index ba8237983..0b0816009 100644 --- a/plugins/feature/map/map/map.qml +++ b/plugins/feature/map/map/map.qml @@ -1,8 +1,8 @@ -import QtQuick 2.12 -import QtQuick.Window 2.12 -import QtQuick.Controls 2.12 -import QtLocation 5.12 -import QtPositioning 5.12 +import QtQuick 2.14 +import QtQuick.Window 2.14 +import QtQuick.Controls 2.14 +import QtLocation 5.14 +import QtPositioning 5.14 Item { id: qmlMap @@ -14,16 +14,16 @@ Item { function createMap(pluginParameters) { var parameters = new Array() for (var prop in pluginParameters) { - var parameter = Qt.createQmlObject('import QtLocation 5.6; PluginParameter{ name: "'+ prop + '"; value: "' + pluginParameters[prop]+'"}', qmlMap) + var parameter = Qt.createQmlObject('import QtLocation 5.14; PluginParameter{ name: "'+ prop + '"; value: "' + pluginParameters[prop]+'"}', qmlMap) parameters.push(parameter) } qmlMap.mapParameters = parameters var plugin if (mapParameters && mapParameters.length > 0) - plugin = Qt.createQmlObject ('import QtLocation 5.12; Plugin{ name:"' + mapProvider + '"; parameters: qmlMap.mapParameters}', qmlMap) + plugin = Qt.createQmlObject ('import QtLocation 5.14; Plugin{ name:"' + mapProvider + '"; parameters: qmlMap.mapParameters}', qmlMap) else - plugin = Qt.createQmlObject ('import QtLocation 5.12; Plugin{ name:"' + mapProvider + '"}', qmlMap) + plugin = Qt.createQmlObject ('import QtLocation 5.14; Plugin{ name:"' + mapProvider + '"}', qmlMap) if (mapPtr) { // Objects aren't destroyed immediately, so rename the old // map, so any C++ code that calls findChild("map") doesn't find @@ -66,6 +66,27 @@ Item { center: QtPositioning.coordinate(51.5, 0.125) // London zoomLevel: 10 + // Tracks first, so drawn under other items + MapItemView { + model: mapModel + delegate: groundTrack1Component + } + + MapItemView { + model: mapModel + delegate: groundTrack2Component + } + + MapItemView { + model: mapModel + delegate: predictedGroundTrack1Component + } + + MapItemView { + model: mapModel + delegate: predictedGroundTrack2Component + } + MapItemView { model: mapModel delegate: mapComponent @@ -73,12 +94,25 @@ Item { onZoomLevelChanged: { mapZoomLevel = zoomLevel + } + // The map displays MapPolyLines in the wrong place (+360 degrees) if + // they start to the left of the visible region, so we need to + // split them so they don't, each time the visible region is changed. meh. + onCenterChanged: { + mapModel.viewChanged(visibleRegion.boundingGeoRectangle().bottomLeft.longitude, visibleRegion.boundingGeoRectangle().bottomRight.longitude); } } } + function mapRect() { + if (mapPtr) + return mapPtr.visibleRegion.boundingGeoRectangle(); + else + return null; + } + Component { id: mapComponent MapQuickItem { @@ -87,6 +121,7 @@ Item { anchorPoint.y: image.height/2 coordinate: position zoomLevel: mapZoomLevel > mapImageMinZoom ? mapZoomLevel : mapImageMinZoom + autoFadeIn: false // not in 5.12 sourceItem: Grid { id: gridItem @@ -185,4 +220,46 @@ Item { } } + Component { + id: predictedGroundTrack1Component + MapPolyline { + line.width: 2 + line.color: predictedGroundTrackColor + path: predictedGroundTrack1 + autoFadeIn: false + } + } + + // Part of the line that crosses edge of map + Component { + id: predictedGroundTrack2Component + MapPolyline { + line.width: 2 + line.color: predictedGroundTrackColor + path: predictedGroundTrack2 + autoFadeIn: false + } + } + + Component { + id: groundTrack1Component + MapPolyline { + line.width: 2 + line.color: groundTrackColor + path: groundTrack1 + autoFadeIn: false + } + } + + // Part of the line that crosses edge of map + Component { + id: groundTrack2Component + MapPolyline { + line.width: 2 + line.color: groundTrackColor + path: groundTrack2 + autoFadeIn: false + } + } + } diff --git a/plugins/feature/map/map/map_5_12.qml b/plugins/feature/map/map/map_5_12.qml new file mode 100644 index 000000000..34c97404c --- /dev/null +++ b/plugins/feature/map/map/map_5_12.qml @@ -0,0 +1,261 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 2.12 +import QtLocation 5.12 +import QtPositioning 5.12 + +Item { + id: qmlMap + property int mapZoomLevel: 11 + property string mapProvider: "osm" + property variant mapParameters + property variant mapPtr + + function createMap(pluginParameters) { + var parameters = new Array() + for (var prop in pluginParameters) { + var parameter = Qt.createQmlObject('import QtLocation 5.6; PluginParameter{ name: "'+ prop + '"; value: "' + pluginParameters[prop]+'"}', qmlMap) + parameters.push(parameter) + } + qmlMap.mapParameters = parameters + + var plugin + if (mapParameters && mapParameters.length > 0) + plugin = Qt.createQmlObject ('import QtLocation 5.12; Plugin{ name:"' + mapProvider + '"; parameters: qmlMap.mapParameters}', qmlMap) + else + plugin = Qt.createQmlObject ('import QtLocation 5.12; Plugin{ name:"' + mapProvider + '"}', qmlMap) + if (mapPtr) { + // Objects aren't destroyed immediately, so rename the old + // map, so any C++ code that calls findChild("map") doesn't find + // the old map + mapPtr.objectName = "oldMap"; + mapPtr.destroy() + } + mapPtr = actualMapComponent.createObject(page) + mapPtr.plugin = plugin; + mapPtr.forceActiveFocus() + mapPtr.objectName = "map"; + } + + function getMapTypes() { + var mapTypes = [] + if (mapPtr) { + for (var i = 0; i < mapPtr.supportedMapTypes.length; i++) { + mapTypes[i] = mapPtr.supportedMapTypes[i].name + } + } + return mapTypes + } + + function setMapType(mapTypeIndex) { + if (mapPtr) + mapPtr.activeMapType = mapPtr.supportedMapTypes[mapTypeIndex] + } + + Item { + id: page + anchors.fill: parent + } + + Component { + id: actualMapComponent + + Map { + id: map + anchors.fill: parent + center: QtPositioning.coordinate(51.5, 0.125) // London + zoomLevel: 10 + + // Tracks first, so drawn under other items + MapItemView { + model: mapModel + delegate: groundTrack1Component + } + + MapItemView { + model: mapModel + delegate: groundTrack2Component + } + + MapItemView { + model: mapModel + delegate: predictedGroundTrack1Component + } + + MapItemView { + model: mapModel + delegate: predictedGroundTrack2Component + } + + MapItemView { + model: mapModel + delegate: mapComponent + } + + onZoomLevelChanged: { + mapZoomLevel = zoomLevel + } + + // The map displays MapPolyLines in the wrong place (+360 degrees) if + // they start to the left of the visible region, so we need to + // split them so they don't, each time the visible region is changed. meh. + onCenterChanged: { + mapModel.viewChanged(visibleRegion.boundingGeoRectangle().bottomLeft.longitude, visibleRegion.boundingGeoRectangle().bottomRight.longitude); + } + + } + } + + function mapRect() { + if (mapPtr) + return mapPtr.visibleRegion.boundingGeoRectangle(); + else + return null; + } + + Component { + id: mapComponent + MapQuickItem { + id: mapElement + anchorPoint.x: image.width/2 + anchorPoint.y: image.height/2 + coordinate: position + zoomLevel: mapZoomLevel > mapImageMinZoom ? mapZoomLevel : mapImageMinZoom + //autoFadeIn: false // not in 5.12 + + sourceItem: Grid { + id: gridItem + columns: 1 + Grid { + horizontalItemAlignment: Grid.AlignHCenter + columnSpacing: 5 + layer.enabled: true + layer.smooth: true + Image { + id: image + rotation: mapImageRotation + source: mapImage + visible: mapImageVisible + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + if (mouse.button === Qt.LeftButton) { + selected = !selected + if (selected) { + mapModel.moveToFront(index) + } + } else if (mouse.button === Qt.RightButton) { + if (frequency > 0) { + freqMenuItem.text = "Set frequency to " + frequencyString + freqMenuItem.enabled = true + } else { + freqMenuItem.text = "No frequency available" + freqMenuItem.enabled = false + } + contextMenu.popup() + } + } + } + } + Rectangle { + id: bubble + color: bubbleColour + border.width: 1 + width: text.width + 5 + height: text.height + 5 + radius: 5 + visible: mapTextVisible + Text { + id: text + anchors.centerIn: parent + text: mapText + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + if (mouse.button === Qt.LeftButton) { + selected = !selected + if (selected) { + mapModel.moveToFront(index) + } + } else if (mouse.button === Qt.RightButton) { + if (frequency > 0) { + freqMenuItem.text = "Set frequency to " + frequencyString + freqMenuItem.enabled = true + } else { + freqMenuItem.text = "No frequency available" + freqMenuItem.enabled = false + } + contextMenu.popup() + } + } + Menu { + id: contextMenu + MenuItem { + text: "Set as target" + onTriggered: target = true + } + MenuItem { + id: freqMenuItem + text: "Not set" + onTriggered: mapModel.setFrequency(frequency) + } + MenuItem { + text: "Move to front" + onTriggered: mapModel.moveToFront(index) + } + MenuItem { + text: "Move to back" + onTriggered: mapModel.moveToBack(index) + } + } + } + } + } + } + } + } + + Component { + id: predictedGroundTrack1Component + MapPolyline { + line.width: 2 + line.color: predictedGroundTrackColor + path: predictedGroundTrack1 + } + } + + // Part of the line that crosses edge of map + Component { + id: predictedGroundTrack2Component + MapPolyline { + line.width: 2 + line.color: predictedGroundTrackColor + path: predictedGroundTrack2 + } + } + + Component { + id: groundTrack1Component + MapPolyline { + line.width: 2 + line.color: groundTrackColor + path: groundTrack1 + } + } + + // Part of the line that crosses edge of map + Component { + id: groundTrack2Component + MapPolyline { + line.width: 2 + line.color: groundTrackColor + path: groundTrack2 + } + } + +} diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index ed5570cbb..5b8866570 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -139,6 +139,42 @@ QVariant MapModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(m_items[row]->m_frequency); else if (role == MapModel::frequencyStringRole) return QVariant::fromValue(m_items[row]->m_frequencyString); + else if (role == MapModel::predictedGroundTrack1Role) + { + if ((m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) && (m_sources & m_items[row]->m_sourceMask)) + return m_items[row]->m_predictedTrack1; + else + return QVariantList(); + } + else if (role == MapModel::predictedGroundTrack2Role) + { + if ((m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) && (m_sources & m_items[row]->m_sourceMask)) + return m_items[row]->m_predictedTrack2; + else + return QVariantList(); + } + else if (role == MapModel::groundTrack1Role) + { + if ((m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) && (m_sources & m_items[row]->m_sourceMask)) + return m_items[row]->m_takenTrack1; + else + return QVariantList(); + } + else if (role == MapModel::groundTrack2Role) + { + if ((m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) && (m_sources & m_items[row]->m_sourceMask)) + return m_items[row]->m_takenTrack2; + else + return QVariantList(); + } + else if (role == groundTrackColorRole) + { + return m_groundTrackColor; + } + else if (role == predictedGroundTrackColorRole) + { + return m_predictedGroundTrackColor; + } return QVariant(); } @@ -193,6 +229,7 @@ void MapModel::update(const PipeEndPoint *sourcePipe, SWGSDRangel::SWGMapItem *s { // Update the item item->update(swgMapItem); + splitTracks(item); update(item); } } @@ -235,6 +272,312 @@ void MapModel::updateTarget() } } +void MapModel::splitTracks(MapItem *item) +{ + if (item->m_takenTrackCoords.size() > 1) + splitTrack(item->m_takenTrackCoords, item->m_takenTrack, item->m_takenTrack1, item->m_takenTrack2, + item->m_takenStart1, item->m_takenStart2, item->m_takenEnd1, item->m_takenEnd2); + if (item->m_predictedTrackCoords.size() > 1) + splitTrack(item->m_predictedTrackCoords, item->m_predictedTrack, item->m_predictedTrack1, item->m_predictedTrack2, + item->m_predictedStart1, item->m_predictedStart2, item->m_predictedEnd1, item->m_predictedEnd2); +} + +void MapModel::interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen) +{ + double x1 = c1->longitude(); + double y1 = c1->latitude(); + double x2 = c2->longitude(); + double y2 = c2->latitude(); + double y; + if (x2 < x1) + x2 += 360.0; + if (x < x1) + x += 360.0; + y = interpolate(x1, y1, x2, y2, x); + if (x > 180) + x -= 360.0; + if (offScreen) + x -= 0.000000001; + else + x += 0.000000001; + ci->setLongitude(x); + ci->setLatitude(y); + ci->setAltitude(c1->altitude()); +} + +void MapModel::interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen) +{ + double x1 = c1->longitude(); + double y1 = c1->latitude(); + double x2 = c2->longitude(); + double y2 = c2->latitude(); + double y; + if (x2 > x1) + x2 -= 360.0; + if (x > x1) + x -= 360.0; + y = interpolate(x1, y1, x2, y2, x); + if (x < -180) + x += 360.0; + if (offScreen) + x += 0.000000001; + else + x -= 0.000000001; + ci->setLongitude(x); + ci->setLatitude(y); + ci->setAltitude(c1->altitude()); +} + +static bool isOnScreen(double lon, double bottomLeftLongitude, double bottomRightLongitude, double width, bool antimed) +{ + bool onScreen = false; + if (width == 360) + onScreen = true; + else if (!antimed) + onScreen = (lon > bottomLeftLongitude) && (lon <= bottomRightLongitude); + else + onScreen = (lon > bottomLeftLongitude) || (lon <= bottomRightLongitude); + return onScreen; +} + +static bool crossesAntimeridian(double prevLon, double lon) +{ + bool crosses = false; + if ((prevLon > 90) && (lon < -90)) + crosses = true; // West to East + else if ((prevLon < -90) && (lon > 90)) + crosses = true; // East to West + return crosses; +} + +static bool crossesAntimeridianEast(double prevLon, double lon) +{ + bool crosses = false; + if ((prevLon > 90) && (lon < -90)) + crosses = true; // West to East + return crosses; +} + +static bool crossesAntimeridianWest(double prevLon, double lon) +{ + bool crosses = false; + if ((prevLon < -90) && (lon > 90)) + crosses = true; // East to West + return crosses; +} + +static bool crossesEdge(double lon, double prevLon, double bottomLeftLongitude, double bottomRightLongitude) +{ + // Determine if antimerdian is between the two points + if (!crossesAntimeridian(prevLon, lon)) + { + bool crosses = false; + if ((prevLon <= bottomRightLongitude) && (lon > bottomRightLongitude)) + crosses = true; // Crosses right edge East + else if ((prevLon >= bottomRightLongitude) && (lon < bottomRightLongitude)) + crosses = true; // Crosses right edge West + else if ((prevLon >= bottomLeftLongitude) && (lon < bottomLeftLongitude)) + crosses = true; // Crosses left edge West + else if ((prevLon <= bottomLeftLongitude) && (lon > bottomLeftLongitude)) + crosses = true; // Crosses left edge East + return crosses; + } + else + { + // Determine which point and the edge the antimerdian is between + bool prevLonToRightCrossesAnti = crossesAntimeridianEast(prevLon, bottomRightLongitude); + bool rightToLonCrossesAnti = crossesAntimeridianEast(bottomRightLongitude, lon); + bool prevLonToLeftCrossesAnti = crossesAntimeridianWest(prevLon, bottomLeftLongitude); + bool leftToLonCrossesAnti = crossesAntimeridianWest(bottomLeftLongitude, lon); + + bool crosses = false; + if ( ((prevLon > bottomRightLongitude) && prevLonToRightCrossesAnti && (lon > bottomRightLongitude)) + || ((prevLon <= bottomRightLongitude) && (lon <= bottomRightLongitude) && rightToLonCrossesAnti) + ) + crosses = true; // Crosses right edge East + else if ( ((prevLon < bottomRightLongitude) && prevLonToRightCrossesAnti && (lon < bottomRightLongitude)) + || ((prevLon >= bottomRightLongitude) && (lon >= bottomRightLongitude) && rightToLonCrossesAnti) + ) + crosses = true; // Crosses right edge West + else if ( ((prevLon < bottomLeftLongitude) && prevLonToLeftCrossesAnti && (lon < bottomLeftLongitude)) + || ((prevLon >= bottomLeftLongitude) && (lon >= bottomLeftLongitude) && leftToLonCrossesAnti) + ) + crosses = true; // Crosses left edge West + else if ( ((prevLon > bottomLeftLongitude) && prevLonToLeftCrossesAnti && (lon > bottomLeftLongitude)) + || ((prevLon <= bottomLeftLongitude) && (lon <= bottomLeftLongitude) && leftToLonCrossesAnti) + ) + crosses = true; // Crosses left edge East + return crosses; + } +} + +void MapModel::interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen) +{ + double x1 = c1->longitude(); + double x2 = c2->longitude(); + double crossesAnti = crossesAntimeridian(x1, x2); + double x; + + // Need to work out which edge we're interpolating too + // and whether antimeridian is in the way, as that flips x1x2 + + if (((x1 < x2) && !crossesAnti) || ((x1 > x2) && crossesAnti)) + { + x = offScreen ? bottomRightLongitude : bottomLeftLongitude; + interpolateEast(c1, c2, x, ci, offScreen); + } + else + { + x = offScreen ? bottomLeftLongitude : bottomRightLongitude; + interpolateWest(c1, c2, x, ci, offScreen); + } +} + +void MapModel::splitTrack(const QList& coords, const QVariantList& track, + QVariantList& track1, QVariantList& track2, + QGeoCoordinate& start1, QGeoCoordinate& start2, + QGeoCoordinate& end1, QGeoCoordinate& end2) +{ + /* + QStringList l; + for (int i = 0; i < track.size(); i++) + { + QGeoCoordinate c = track[i].value(); + l.append(QString("%1").arg((int)c.longitude())); + } + qDebug() << "Init T: " << l; + */ + + QQuickItem* map = m_gui->getMapItem(); + QVariant rectVariant; + QMetaObject::invokeMethod(map, "mapRect", Q_RETURN_ARG(QVariant, rectVariant)); + QGeoRectangle rect = qvariant_cast(rectVariant); + double bottomLeftLongitude = rect.bottomLeft().longitude(); + double bottomRightLongitude = rect.bottomRight().longitude(); + + int width = round(rect.width()); + bool antimed = (width == 360) || (bottomLeftLongitude > bottomRightLongitude); + + /* + qDebug() << "Anitmed visible: " << antimed; + qDebug() << "bottomLeftLongitude: " << bottomLeftLongitude; + qDebug() << "bottomRightLongitude: " << bottomRightLongitude; + */ + + track1.clear(); + track2.clear(); + + double lon, prevLon; + bool onScreen, prevOnScreen; + QList tracks({&track1, &track2}); + QList ends({&end1, &end2}); + QList starts({&start1, &start2}); + int trackIdx = 0; + for (int i = 0; i < coords.size(); i++) + { + lon = coords[i]->longitude(); + if (i == 0) + { + prevLon = lon; + prevOnScreen = true; // To avoid interpolation for first point + } + // Can be onscreen after having crossed edge from other side + // Or can be onscreen after previously having been off screen + onScreen = isOnScreen(lon, bottomLeftLongitude, bottomRightLongitude, width, antimed); + bool crossedEdge = crossesEdge(lon, prevLon, bottomLeftLongitude, bottomRightLongitude); + if ((onScreen && !crossedEdge) || (onScreen && !prevOnScreen)) + { + if ((i > 0) && (tracks[trackIdx]->size() == 0)) // Could also use (onScreen && !prevOnScreen)? + { + if (trackIdx >= starts.size()) + break; + // Interpolate from edge of screen + interpolate(coords[i-1], coords[i], bottomLeftLongitude, bottomRightLongitude, starts[trackIdx], false); + tracks[trackIdx]->append(QVariant::fromValue(*starts[trackIdx])); + } + tracks[trackIdx]->append(track[i]); + } + else if (tracks[trackIdx]->size() > 0) + { + // Either we've crossed to the other side, or have gone off screen + if (trackIdx >= ends.size()) + break; + // Interpolate to edge of screen + interpolate(coords[i-1], coords[i], bottomLeftLongitude, bottomRightLongitude, ends[trackIdx], true); + tracks[trackIdx]->append(QVariant::fromValue(*ends[trackIdx])); + // Start new track + trackIdx++; + if (trackIdx >= tracks.size()) + { + // This can happen with highly retrograde orbits, where trace 90% of period + // will cover more than 360 degrees - delete last point as Map + // will not be able to display it properly + tracks[trackIdx-1]->removeLast(); + break; + } + if (onScreen) + { + // Interpolate from edge of screen + interpolate(coords[i-1], coords[i], bottomLeftLongitude, bottomRightLongitude, starts[trackIdx], false); + tracks[trackIdx]->append(QVariant::fromValue(*starts[trackIdx])); + tracks[trackIdx]->append(track[i]); + } + } + prevLon = lon; + prevOnScreen = onScreen; + } + + /* + l.clear(); + for (int i = 0; i < track1.size(); i++) + { + QGeoCoordinate c = track1[i].value(); + if (!c.isValid()) + l.append("Invalid!"); + else + l.append(QString("%1").arg(c.longitude(), 0, 'f', 1)); + } + qDebug() << "T1: " << l; + + l.clear(); + for (int i = 0; i < track2.size(); i++) + { + QGeoCoordinate c = track2[i].value(); + if (!c.isValid()) + l.append("Invalid!"); + else + l.append(QString("%1").arg(c.longitude(), 0, 'f', 1)); + } + qDebug() << "T2: " << l; + */ +} + +void MapModel::viewChanged(double bottomLeftLongitude, double bottomRightLongitude) +{ + (void) bottomRightLongitude; + if (!std::isnan(bottomLeftLongitude)) + { + for (int row = 0; row < m_items.size(); row++) + { + MapItem *item = m_items[row]; + if (item->m_takenTrackCoords.size() > 1) + { + splitTrack(item->m_takenTrackCoords, item->m_takenTrack, item->m_takenTrack1, item->m_takenTrack2, + item->m_takenStart1, item->m_takenStart2, item->m_takenEnd1, item->m_takenEnd2); + QModelIndex idx = index(row); + emit dataChanged(idx, idx); + } + if (item->m_predictedTrackCoords.size() > 1) + { + splitTrack(item->m_predictedTrackCoords, item->m_predictedTrack, item->m_predictedTrack1, item->m_predictedTrack2, + item->m_predictedStart1, item->m_predictedStart2, item->m_predictedEnd1, item->m_predictedEnd2); + QModelIndex idx = index(row); + emit dataChanged(idx, idx); + } + } + } +} + MapGUI* MapGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) { MapGUI* gui = new MapGUI(pluginAPI, featureUISet, feature); @@ -341,7 +684,12 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur ui->setupUi(this); ui->map->rootContext()->setContextProperty("mapModel", &m_mapModel); + // 5.12 doesn't display map items when fully zoomed out +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map/map_5_12.qml"))); +#else ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map/map.qml"))); +#endif setAttribute(Qt::WA_DeleteOnClose, true); setChannelWidget(false); @@ -408,7 +756,9 @@ void MapGUI::setBeacons(QList *beacons) { Beacon *beacon = i.next(); SWGSDRangel::SWGMapItem beaconMapItem; - beaconMapItem.setName(new QString(beacon->m_callsign)); + // Need to suffix frequency, as there are multiple becaons with same callsign at different locations + QString name = QString("%1-%2").arg(beacon->m_callsign).arg(beacon->getFrequencyShortText()); + beaconMapItem.setName(new QString(name)); beaconMapItem.setLatitude(beacon->m_latitude); beaconMapItem.setLongitude(beacon->m_longitude); beaconMapItem.setAltitude(beacon->m_altitude); @@ -487,8 +837,14 @@ void MapGUI::displaySettings() setWindowTitle(m_settings.m_title); blockApplySettings(true); ui->displayNames->setChecked(m_settings.m_displayNames); + ui->displaySelectedGroundTracks->setChecked(m_settings.m_displaySelectedGroundTracks); + ui->displayAllGroundTracks->setChecked(m_settings.m_displayAllGroundTracks); m_mapModel.setDisplayNames(m_settings.m_displayNames); + m_mapModel.setDisplaySelectedGroundTracks(m_settings.m_displaySelectedGroundTracks); + m_mapModel.setDisplayAllGroundTracks(m_settings.m_displayAllGroundTracks); m_mapModel.setSources(m_settings.m_sources); + m_mapModel.setGroundTrackColor(m_settings.m_groundTrackColor); + m_mapModel.setPredictedGroundTrackColor(m_settings.m_predictedGroundTrackColor); applyMapSettings(); blockApplySettings(false); } @@ -555,6 +911,18 @@ void MapGUI::on_displayNames_clicked(bool checked) m_mapModel.setDisplayNames(checked); } +void MapGUI::on_displaySelectedGroundTracks_clicked(bool checked) +{ + m_settings.m_displaySelectedGroundTracks = checked; + m_mapModel.setDisplaySelectedGroundTracks(checked); +} + +void MapGUI::on_displayAllGroundTracks_clicked(bool checked) +{ + m_settings.m_displayAllGroundTracks = checked; + m_mapModel.setDisplayAllGroundTracks(checked); +} + void MapGUI::on_find_returnPressed() { find(ui->find->text().trimmed()); @@ -655,6 +1023,8 @@ void MapGUI::on_displaySettings_clicked() applySettings(); if (dialog.m_sourcesChanged) m_mapModel.setSources(m_settings.m_sources); + m_mapModel.setGroundTrackColor(m_settings.m_groundTrackColor); + m_mapModel.setPredictedGroundTrackColor(m_settings.m_predictedGroundTrackColor); } } @@ -691,3 +1061,7 @@ QString MapGUI::getBeaconFilename() { return MapGUI::getDataDir() + "/iaru_beacons.csv"; } + +QQuickItem *MapGUI::getMapItem() { + return ui->map->rootObject(); +} diff --git a/plugins/feature/map/mapgui.h b/plugins/feature/map/mapgui.h index 5b8fcfd4a..3bc618ea3 100644 --- a/plugins/feature/map/mapgui.h +++ b/plugins/feature/map/mapgui.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "feature/featuregui.h" #include "util/messagequeue.h" @@ -41,6 +42,7 @@ namespace Ui { class MapGUI; class MapModel; +class QQuickItem; struct Beacon; // Information required about each item displayed on the map @@ -62,6 +64,8 @@ public: if (text != nullptr) m_text = *text; findFrequency(); + updateTrack(mapItem->getTrack()); + updatePredictedTrack(mapItem->getPredictedTrack()); } void update(SWGSDRangel::SWGMapItem *mapItem) @@ -76,6 +80,8 @@ public: if (text != nullptr) m_text = *text; findFrequency(); + updateTrack(mapItem->getTrack()); + updatePredictedTrack(mapItem->getPredictedTrack()); } QGeoCoordinate getCoordinates() @@ -90,6 +96,64 @@ private: void findFrequency(); + void updateTrack(QList *track) + { + if (track != nullptr) + { + qDeleteAll(m_takenTrackCoords); + m_takenTrackCoords.clear(); + m_takenTrack.clear(); + m_takenTrack1.clear(); + m_takenTrack2.clear(); + for (int i = 0; i < track->size(); i++) + { + SWGSDRangel::SWGMapCoordinate* p = track->at(i); + QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); + m_takenTrackCoords.push_back(c); + m_takenTrack.push_back(QVariant::fromValue(*c)); + } + } + else + { + // Automatically create a track + if (m_takenTrackCoords.size() == 0) + { + QGeoCoordinate *c = new QGeoCoordinate(m_latitude, m_longitude, m_altitude); + m_takenTrackCoords.push_back(c); + m_takenTrack.push_back(QVariant::fromValue(*c)); + } + else + { + QGeoCoordinate *prev = m_takenTrackCoords.last(); + if ((prev->latitude() != m_latitude) || (prev->longitude() != m_longitude) || (prev->altitude() != m_altitude)) + { + QGeoCoordinate *c = new QGeoCoordinate(m_latitude, m_longitude, m_altitude); + m_takenTrackCoords.push_back(c); + m_takenTrack.push_back(QVariant::fromValue(*c)); + } + } + } + } + + void updatePredictedTrack(QList *track) + { + if (track != nullptr) + { + qDeleteAll(m_predictedTrackCoords); + m_predictedTrackCoords.clear(); + m_predictedTrack.clear(); + m_predictedTrack1.clear(); + m_predictedTrack2.clear(); + for (int i = 0; i < track->size(); i++) + { + SWGSDRangel::SWGMapCoordinate* p = track->at(i); + QGeoCoordinate *c = new QGeoCoordinate(p->getLatitude(), p->getLongitude(), p->getAltitude()); + m_predictedTrackCoords.push_back(c); + m_predictedTrack.push_back(QVariant::fromValue(*c)); + } + } + } + friend MapModel; const PipeEndPoint *m_sourcePipe; // Channel/feature that created the item quint32 m_sourceMask; // Source bitmask as per MapSettings::SOURCE_* constants @@ -103,6 +167,22 @@ private: QString m_text; double m_frequency; // Frequency to set QString m_frequencyString; + QList m_predictedTrackCoords; + QVariantList m_predictedTrack; // Line showing where the object is going + QVariantList m_predictedTrack1; + QVariantList m_predictedTrack2; + QGeoCoordinate m_predictedStart1; + QGeoCoordinate m_predictedStart2; + QGeoCoordinate m_predictedEnd1; + QGeoCoordinate m_predictedEnd2; + QList m_takenTrackCoords; + QVariantList m_takenTrack; // Line showing where the object has been + QVariantList m_takenTrack1; + QVariantList m_takenTrack2; + QGeoCoordinate m_takenStart1; + QGeoCoordinate m_takenStart2; + QGeoCoordinate m_takenEnd1; + QGeoCoordinate m_takenEnd2; }; // Model used for each item on the map @@ -123,7 +203,13 @@ public: selectedRole = Qt::UserRole + 9, targetRole = Qt::UserRole + 10, frequencyRole = Qt::UserRole + 11, - frequencyStringRole = Qt::UserRole + 12 + frequencyStringRole = Qt::UserRole + 12, + predictedGroundTrack1Role = Qt::UserRole + 13, + predictedGroundTrack2Role = Qt::UserRole + 14, + groundTrack1Role = Qt::UserRole + 15, + groundTrack2Role = Qt::UserRole + 16, + groundTrackColorRole = Qt::UserRole + 17, + predictedGroundTrackColorRole = Qt::UserRole + 18 }; MapModel(MapGUI *gui) : @@ -131,6 +217,8 @@ public: m_target(-1), m_sources(-1) { + setGroundTrackColor(0); + setPredictedGroundTrackColor(0); } Q_INVOKABLE void add(MapItem *item) @@ -275,8 +363,41 @@ public: allUpdated(); } + void setDisplaySelectedGroundTracks(bool displayGroundTracks) + { + m_displaySelectedGroundTracks = displayGroundTracks; + allUpdated(); + } + + void setDisplayAllGroundTracks(bool displayGroundTracks) + { + m_displayAllGroundTracks = displayGroundTracks; + allUpdated(); + } + + void setGroundTrackColor(quint32 color) + { + m_groundTrackColor = QVariant::fromValue(QColor::fromRgb(color)); + } + + void setPredictedGroundTrackColor(quint32 color) + { + m_predictedGroundTrackColor = QVariant::fromValue(QColor::fromRgb(color)); + } + Q_INVOKABLE void setFrequency(double frequency); + void interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen); + void interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen); + void interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen); + + void splitTracks(MapItem *item); + void splitTrack(const QList& coords, const QVariantList& track, + QVariantList& track1, QVariantList& track2, + QGeoCoordinate& start1, QGeoCoordinate& start2, + QGeoCoordinate& end1, QGeoCoordinate& end2); + Q_INVOKABLE void viewChanged(double bottomLeftLongitude, double bottomRightLongitude); + QHash roleNames() const { QHash roles; @@ -292,6 +413,12 @@ public: roles[targetRole] = "target"; roles[frequencyRole] = "frequency"; roles[frequencyStringRole] = "frequencyString"; + roles[predictedGroundTrack1Role] = "predictedGroundTrack1"; + roles[predictedGroundTrack2Role] = "predictedGroundTrack2"; + roles[groundTrack1Role] = "groundTrack1"; + roles[groundTrack2Role] = "groundTrack2"; + roles[groundTrackColorRole] = "groundTrackColor"; + roles[predictedGroundTrackColorRole] = "predictedGroundTrackColor"; return roles; } @@ -302,13 +429,26 @@ public: allUpdated(); } + // Linear interpolation + double interpolate(double x0, double y0, double x1, double y1, double x) + { + return (y0*(x1-x) + y1*(x-x0)) / (x1-x0); + } + private: MapGUI *m_gui; QList m_items; QList m_selected; int m_target; // Row number of current target, or -1 for none bool m_displayNames; + bool m_displaySelectedGroundTracks; + bool m_displayAllGroundTracks; quint32 m_sources; + QVariant m_groundTrackColor; + QVariant m_predictedGroundTrackColor; + + double m_bottomLeftLongitude; + double m_bottomRightLongitude; }; class MapGUI : public FeatureGUI { @@ -323,6 +463,7 @@ public: virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } AzEl *getAzEl() { return &m_azEl; } Map *getMap() { return m_map; } + QQuickItem *getMapItem(); quint32 getSourceMask(const PipeEndPoint *sourcePipe); static QString getBeaconFilename(); QList *getBeacons() { return m_beacons; } @@ -364,6 +505,8 @@ private slots: void onWidgetRolled(QWidget* widget, bool rollDown); void handleInputMessages(); void on_displayNames_clicked(bool checked=false); + void on_displayAllGroundTracks_clicked(bool checked=false); + void on_displaySelectedGroundTracks_clicked(bool checked=false); void on_find_returnPressed(); void on_maidenhead_clicked(); void on_deleteAll_clicked(); diff --git a/plugins/feature/map/mapgui.ui b/plugins/feature/map/mapgui.ui index a6a9a9ca2..05bc51f4a 100644 --- a/plugins/feature/map/mapgui.ui +++ b/plugins/feature/map/mapgui.ui @@ -6,8 +6,8 @@ 0 0 - 462 - 689 + 481 + 750
@@ -42,7 +42,7 @@ 0 0 - 461 + 471 41 @@ -82,9 +82,15 @@
+ + + 0 + 0 + + - 150 + 100 0 @@ -93,19 +99,6 @@
- - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -120,7 +113,7 @@ - + Maidenhead locator conversion @@ -134,7 +127,7 @@ - + Display Beacon dialog @@ -168,7 +161,57 @@ - + + + + Adobe Devanagari + + + + Display ground tracks for selected item + + + ^ + + + + :/logarithmic.png:/logarithmic.png + + + true + + + true + + + + + + + + Adobe Devanagari + + + + Display all ground tracks + + + ^ + + + + :/map/icons/groundtracks.png:/map/icons/groundtracks.png + + + true + + + true + + + + + Delete all items on the map @@ -182,7 +225,7 @@ - + Show settings dialog @@ -203,9 +246,9 @@ 0 - 100 - 461 - 581 + 60 + 471 + 681 @@ -244,7 +287,7 @@ 100 - 500 + 590 @@ -293,6 +336,7 @@ + diff --git a/plugins/feature/map/mapsettings.cpp b/plugins/feature/map/mapsettings.cpp index aa45e824e..e7bd273b1 100644 --- a/plugins/feature/map/mapsettings.cpp +++ b/plugins/feature/map/mapsettings.cpp @@ -26,13 +26,15 @@ const QStringList MapSettings::m_pipeTypes = { QStringLiteral("ADSBDemod"), QStringLiteral("APRS"), - QStringLiteral("StarTracker") + QStringLiteral("StarTracker"), + QStringLiteral("SatelliteTracker") }; const QStringList MapSettings::m_pipeURIs = { QStringLiteral("sdrangel.channel.adsbdemod"), QStringLiteral("sdrangel.feature.aprs"), - QStringLiteral("sdrangel.feature.startracker") + QStringLiteral("sdrangel.feature.startracker"), + QStringLiteral("sdrangel.feature.satellitetracker") }; // GUI combo box should match ordering in this list @@ -55,6 +57,10 @@ void MapSettings::resetToDefaults() m_mapBoxApiKey = ""; m_mapBoxStyles = ""; m_sources = -1; + m_displaySelectedGroundTracks = true; + m_displayAllGroundTracks = true; + m_groundTrackColor = QColor(150, 0, 20).rgb(); + m_predictedGroundTrackColor = QColor(225, 0, 50).rgb(); m_title = "Map"; m_rgbColor = QColor(225, 25, 99).rgb(); m_useReverseAPI = false; @@ -73,6 +79,8 @@ QByteArray MapSettings::serialize() const s.writeString(3, m_mapBoxApiKey); s.writeString(4, m_mapBoxStyles); s.writeU32(5, m_sources); + s.writeU32(6, m_groundTrackColor); + s.writeU32(7, m_predictedGroundTrackColor); s.writeString(8, m_title); s.writeU32(9, m_rgbColor); s.writeBool(10, m_useReverseAPI); @@ -80,6 +88,8 @@ QByteArray MapSettings::serialize() const s.writeU32(12, m_reverseAPIPort); s.writeU32(13, m_reverseAPIFeatureSetIndex); s.writeU32(14, m_reverseAPIFeatureIndex); + s.writeBool(15, m_displaySelectedGroundTracks); + s.writeBool(16, m_displayAllGroundTracks); return s.final(); } @@ -105,6 +115,8 @@ bool MapSettings::deserialize(const QByteArray& data) d.readString(3, &m_mapBoxApiKey, ""); d.readString(4, &m_mapBoxStyles, ""); d.readU32(5, &m_sources, -1); + d.readU32(6, &m_groundTrackColor, QColor(150, 0, 20).rgb()); + d.readU32(7, &m_predictedGroundTrackColor, QColor(225, 0, 50).rgb()); d.readString(8, &m_title, "Map"); d.readU32(9, &m_rgbColor, QColor(225, 25, 99).rgb()); d.readBool(10, &m_useReverseAPI, false); @@ -121,6 +133,8 @@ bool MapSettings::deserialize(const QByteArray& data) m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp; d.readU32(14, &utmp, 0); m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp; + d.readBool(15, &m_displaySelectedGroundTracks, true); + d.readBool(16, &m_displayAllGroundTracks, true); return true; } diff --git a/plugins/feature/map/mapsettings.h b/plugins/feature/map/mapsettings.h index ae5436b5c..8a75937fb 100644 --- a/plugins/feature/map/mapsettings.h +++ b/plugins/feature/map/mapsettings.h @@ -34,6 +34,10 @@ struct MapSettings QString m_mapBoxApiKey; QString m_mapBoxStyles; quint32 m_sources; // Bitmask of SOURCE_* + bool m_displayAllGroundTracks; + bool m_displaySelectedGroundTracks; + quint32 m_groundTrackColor; + quint32 m_predictedGroundTrackColor; QString m_title; quint32 m_rgbColor; bool m_useReverseAPI; @@ -56,8 +60,9 @@ struct MapSettings static const quint32 SOURCE_ADSB = 0x1; static const quint32 SOURCE_APRS = 0x2; static const quint32 SOURCE_STAR_TRACKER = 0x4; - static const quint32 SOURCE_BEACONS = 0x8; - static const quint32 SOURCE_STATION = 0x10; + static const quint32 SOURCE_SATELLITE_TRACKER = 0x8; + static const quint32 SOURCE_BEACONS = 0x10; + static const quint32 SOURCE_STATION = 0x20; }; #endif // INCLUDE_FEATURE_MAPSETTINGS_H_ diff --git a/plugins/feature/map/mapsettingsdialog.cpp b/plugins/feature/map/mapsettingsdialog.cpp index 1133dd380..992e3b8b1 100644 --- a/plugins/feature/map/mapsettingsdialog.cpp +++ b/plugins/feature/map/mapsettingsdialog.cpp @@ -16,12 +16,25 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include +#include #include "util/units.h" #include "mapsettingsdialog.h" #include "maplocationdialog.h" +static QString rgbToColor(quint32 rgb) +{ + QColor color = QColor::fromRgb(rgb); + return QString("%1,%2,%3").arg(color.red()).arg(color.green()).arg(color.blue()); +} + +static QString backgroundCSS(quint32 rgb) +{ + return QString("QToolButton { background:rgb(%1); }").arg(rgbToColor(rgb)); +} + MapSettingsDialog::MapSettingsDialog(MapSettings *settings, QWidget* parent) : QDialog(parent), m_settings(settings), @@ -33,6 +46,8 @@ MapSettingsDialog::MapSettingsDialog(MapSettings *settings, QWidget* parent) : ui->mapBoxStyles->setText(settings->m_mapBoxStyles); for (int i = 0; i < ui->sourceList->count(); i++) ui->sourceList->item(i)->setCheckState((m_settings->m_sources & (1 << i)) ? Qt::Checked : Qt::Unchecked); + ui->groundTrackColor->setStyleSheet(backgroundCSS(m_settings->m_groundTrackColor)); + ui->predictedGroundTrackColor->setStyleSheet(backgroundCSS(m_settings->m_predictedGroundTrackColor)); } MapSettingsDialog::~MapSettingsDialog() @@ -64,3 +79,23 @@ void MapSettingsDialog::accept() m_settings->m_sources = sources; QDialog::accept(); } + +void MapSettingsDialog::on_groundTrackColor_clicked() +{ + QColorDialog dialog(QColor::fromRgb(m_settings->m_groundTrackColor), this); + if (dialog.exec() == QDialog::Accepted) + { + m_settings->m_groundTrackColor = dialog.selectedColor().rgb(); + ui->groundTrackColor->setStyleSheet(backgroundCSS(m_settings->m_groundTrackColor)); + } +} + +void MapSettingsDialog::on_predictedGroundTrackColor_clicked() +{ + QColorDialog dialog(QColor::fromRgb(m_settings->m_predictedGroundTrackColor), this); + if (dialog.exec() == QDialog::Accepted) + { + m_settings->m_predictedGroundTrackColor = dialog.selectedColor().rgb(); + ui->predictedGroundTrackColor->setStyleSheet(backgroundCSS(m_settings->m_predictedGroundTrackColor)); + } +} diff --git a/plugins/feature/map/mapsettingsdialog.h b/plugins/feature/map/mapsettingsdialog.h index c866cc432..d3b49a9c7 100644 --- a/plugins/feature/map/mapsettingsdialog.h +++ b/plugins/feature/map/mapsettingsdialog.h @@ -34,6 +34,8 @@ public: private slots: void accept(); + void on_groundTrackColor_clicked(); + void on_predictedGroundTrackColor_clicked(); private: Ui::MapSettingsDialog* ui; diff --git a/plugins/feature/map/mapsettingsdialog.ui b/plugins/feature/map/mapsettingsdialog.ui index da40f01e6..8ac4c5eaa 100644 --- a/plugins/feature/map/mapsettingsdialog.ui +++ b/plugins/feature/map/mapsettingsdialog.ui @@ -65,6 +65,14 @@ Checked + + + Satellite Tracker + + + Checked + + Beacons @@ -76,7 +84,50 @@ - + + + Colours + + + + + + Ground tracks (predicted) + + + + + + + Ground tracks (taken) + + + + + + + Select color for predicted ground tracks + + + + + + + + + + Select color for taken ground tracks + + + + + + + + + + + Map Provider Settings diff --git a/plugins/feature/map/readme.md b/plugins/feature/map/readme.md index 1a4974e52..86efe3203 100644 --- a/plugins/feature/map/readme.md +++ b/plugins/feature/map/readme.md @@ -3,8 +3,15 @@

Introduction

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. ![Map feature](../../../doc/img/Map_plugin_beacons.png) @@ -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 + +![Satellite Tracker feature plugin GUI](../../../doc/img/SatelliteTracker_plugin.png) + +

Interface

+ +![Satellite Tracker settings](../../../doc/img/SatelliteTracker_plugin_settings.png) + +

1: Start/Stop plugin

+ +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. + +![SDRangel Control dialog](../../../doc/img/SatelliteTracker_plugin_control.png) + +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. + +![Satellite Selection dialog](../../../doc/img/SatelliteTracker_plugin_selection.png) + +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. + +![Satellite tracker settings dialog](../../../doc/img/SatelliteTracker_plugin_settingsdialog1.png) + +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. + +![Satellite tracker settings dialog](../../../doc/img/SatelliteTracker_plugin_settingsdialog2.png) + +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. + +![Satellite tracker settings dialog](../../../doc/img/SatelliteTracker_plugin_settingsdialog3.png) + +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: + +![Satellite tracker settings dialog](../../../doc/img/SatelliteTracker_plugin_passchart.png) + +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. + +![Satellite data table](../../../doc/img/SatelliteTracker_plugin_satdata.png) + +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. + +![SatelliteTracker map](../../../doc/img/SatelliteTracker_plugin_map.png) + +

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 QGraphicsView
QtCharts
+ + WrappingDateTimeEdit + QDateTimeEdit +
gui/wrappingdatetimeedit.h
+ 1 +
startStop viewOnMap + downloadSolarFlux useMyPosition displaySettings latitude @@ -608,10 +615,14 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds lst solarFlux target + frequency + beamwidth rightAscension declination azimuth elevation + chartSelect + chartSubSelect chart 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.png arrow_left.png + arrow_right.png star.png swap.png gridpolar.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:
- Generated 2021-02-11T23:51:16.152+01:00 + Generated 2021-02-26T21:05:20.434+01:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions.cpp b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions.cpp new file mode 100644 index 000000000..05d34881a --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions.cpp @@ -0,0 +1,135 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGAPTDemodActions.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGAPTDemodActions::SWGAPTDemodActions(QString* json) { + init(); + this->fromJson(*json); +} + +SWGAPTDemodActions::SWGAPTDemodActions() { + aos = nullptr; + m_aos_isSet = false; + los = nullptr; + m_los_isSet = false; +} + +SWGAPTDemodActions::~SWGAPTDemodActions() { + this->cleanup(); +} + +void +SWGAPTDemodActions::init() { + aos = new SWGAPTDemodActions_aos(); + m_aos_isSet = false; + los = new SWGAPTDemodActions_los(); + m_los_isSet = false; +} + +void +SWGAPTDemodActions::cleanup() { + if(aos != nullptr) { + delete aos; + } + if(los != nullptr) { + delete los; + } +} + +SWGAPTDemodActions* +SWGAPTDemodActions::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGAPTDemodActions::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&aos, pJson["aos"], "SWGAPTDemodActions_aos", "SWGAPTDemodActions_aos"); + + ::SWGSDRangel::setValue(&los, pJson["los"], "SWGAPTDemodActions_los", "SWGAPTDemodActions_los"); + +} + +QString +SWGAPTDemodActions::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGAPTDemodActions::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if((aos != nullptr) && (aos->isSet())){ + toJsonValue(QString("aos"), aos, obj, QString("SWGAPTDemodActions_aos")); + } + if((los != nullptr) && (los->isSet())){ + toJsonValue(QString("los"), los, obj, QString("SWGAPTDemodActions_los")); + } + + return obj; +} + +SWGAPTDemodActions_aos* +SWGAPTDemodActions::getAos() { + return aos; +} +void +SWGAPTDemodActions::setAos(SWGAPTDemodActions_aos* aos) { + this->aos = aos; + this->m_aos_isSet = true; +} + +SWGAPTDemodActions_los* +SWGAPTDemodActions::getLos() { + return los; +} +void +SWGAPTDemodActions::setLos(SWGAPTDemodActions_los* los) { + this->los = los; + this->m_los_isSet = true; +} + + +bool +SWGAPTDemodActions::isSet(){ + bool isObjectUpdated = false; + do{ + if(aos && aos->isSet()){ + isObjectUpdated = true; break; + } + if(los && los->isSet()){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions.h b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions.h new file mode 100644 index 000000000..2c28bb3b5 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions.h @@ -0,0 +1,66 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGAPTDemodActions.h + * + * APTDemod + */ + +#ifndef SWGAPTDemodActions_H_ +#define SWGAPTDemodActions_H_ + +#include + + +#include "SWGAPTDemodActions_aos.h" +#include "SWGAPTDemodActions_los.h" + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGAPTDemodActions: public SWGObject { +public: + SWGAPTDemodActions(); + SWGAPTDemodActions(QString* json); + virtual ~SWGAPTDemodActions(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGAPTDemodActions* fromJson(QString &jsonString) override; + + SWGAPTDemodActions_aos* getAos(); + void setAos(SWGAPTDemodActions_aos* aos); + + SWGAPTDemodActions_los* getLos(); + void setLos(SWGAPTDemodActions_los* los); + + + virtual bool isSet() override; + +private: + SWGAPTDemodActions_aos* aos; + bool m_aos_isSet; + + SWGAPTDemodActions_los* los; + bool m_los_isSet; + +}; + +} + +#endif /* SWGAPTDemodActions_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_aos.cpp b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_aos.cpp new file mode 100644 index 000000000..3a5e1b919 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_aos.cpp @@ -0,0 +1,133 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGAPTDemodActions_aos.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGAPTDemodActions_aos::SWGAPTDemodActions_aos(QString* json) { + init(); + this->fromJson(*json); +} + +SWGAPTDemodActions_aos::SWGAPTDemodActions_aos() { + satellite_name = nullptr; + m_satellite_name_isSet = false; + north_to_south_pass = 0; + m_north_to_south_pass_isSet = false; +} + +SWGAPTDemodActions_aos::~SWGAPTDemodActions_aos() { + this->cleanup(); +} + +void +SWGAPTDemodActions_aos::init() { + satellite_name = new QString(""); + m_satellite_name_isSet = false; + north_to_south_pass = 0; + m_north_to_south_pass_isSet = false; +} + +void +SWGAPTDemodActions_aos::cleanup() { + if(satellite_name != nullptr) { + delete satellite_name; + } + +} + +SWGAPTDemodActions_aos* +SWGAPTDemodActions_aos::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGAPTDemodActions_aos::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&satellite_name, pJson["satelliteName"], "QString", "QString"); + + ::SWGSDRangel::setValue(&north_to_south_pass, pJson["northToSouthPass"], "qint32", ""); + +} + +QString +SWGAPTDemodActions_aos::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGAPTDemodActions_aos::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(satellite_name != nullptr && *satellite_name != QString("")){ + toJsonValue(QString("satelliteName"), satellite_name, obj, QString("QString")); + } + if(m_north_to_south_pass_isSet){ + obj->insert("northToSouthPass", QJsonValue(north_to_south_pass)); + } + + return obj; +} + +QString* +SWGAPTDemodActions_aos::getSatelliteName() { + return satellite_name; +} +void +SWGAPTDemodActions_aos::setSatelliteName(QString* satellite_name) { + this->satellite_name = satellite_name; + this->m_satellite_name_isSet = true; +} + +qint32 +SWGAPTDemodActions_aos::getNorthToSouthPass() { + return north_to_south_pass; +} +void +SWGAPTDemodActions_aos::setNorthToSouthPass(qint32 north_to_south_pass) { + this->north_to_south_pass = north_to_south_pass; + this->m_north_to_south_pass_isSet = true; +} + + +bool +SWGAPTDemodActions_aos::isSet(){ + bool isObjectUpdated = false; + do{ + if(satellite_name && *satellite_name != QString("")){ + isObjectUpdated = true; break; + } + if(m_north_to_south_pass_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_aos.h b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_aos.h new file mode 100644 index 000000000..a88cd022b --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_aos.h @@ -0,0 +1,65 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGAPTDemodActions_aos.h + * + * Acquisition of signal + */ + +#ifndef SWGAPTDemodActions_aos_H_ +#define SWGAPTDemodActions_aos_H_ + +#include + + +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGAPTDemodActions_aos: public SWGObject { +public: + SWGAPTDemodActions_aos(); + SWGAPTDemodActions_aos(QString* json); + virtual ~SWGAPTDemodActions_aos(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGAPTDemodActions_aos* fromJson(QString &jsonString) override; + + QString* getSatelliteName(); + void setSatelliteName(QString* satellite_name); + + qint32 getNorthToSouthPass(); + void setNorthToSouthPass(qint32 north_to_south_pass); + + + virtual bool isSet() override; + +private: + QString* satellite_name; + bool m_satellite_name_isSet; + + qint32 north_to_south_pass; + bool m_north_to_south_pass_isSet; + +}; + +} + +#endif /* SWGAPTDemodActions_aos_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_los.cpp b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_los.cpp new file mode 100644 index 000000000..cff77d266 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_los.cpp @@ -0,0 +1,110 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGAPTDemodActions_los.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGAPTDemodActions_los::SWGAPTDemodActions_los(QString* json) { + init(); + this->fromJson(*json); +} + +SWGAPTDemodActions_los::SWGAPTDemodActions_los() { + satellite_name = nullptr; + m_satellite_name_isSet = false; +} + +SWGAPTDemodActions_los::~SWGAPTDemodActions_los() { + this->cleanup(); +} + +void +SWGAPTDemodActions_los::init() { + satellite_name = new QString(""); + m_satellite_name_isSet = false; +} + +void +SWGAPTDemodActions_los::cleanup() { + if(satellite_name != nullptr) { + delete satellite_name; + } +} + +SWGAPTDemodActions_los* +SWGAPTDemodActions_los::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGAPTDemodActions_los::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&satellite_name, pJson["satelliteName"], "QString", "QString"); + +} + +QString +SWGAPTDemodActions_los::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGAPTDemodActions_los::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(satellite_name != nullptr && *satellite_name != QString("")){ + toJsonValue(QString("satelliteName"), satellite_name, obj, QString("QString")); + } + + return obj; +} + +QString* +SWGAPTDemodActions_los::getSatelliteName() { + return satellite_name; +} +void +SWGAPTDemodActions_los::setSatelliteName(QString* satellite_name) { + this->satellite_name = satellite_name; + this->m_satellite_name_isSet = true; +} + + +bool +SWGAPTDemodActions_los::isSet(){ + bool isObjectUpdated = false; + do{ + if(satellite_name && *satellite_name != QString("")){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_los.h b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_los.h new file mode 100644 index 000000000..4b3410a0f --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodActions_los.h @@ -0,0 +1,59 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGAPTDemodActions_los.h + * + * Loss of signal + */ + +#ifndef SWGAPTDemodActions_los_H_ +#define SWGAPTDemodActions_los_H_ + +#include + + +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGAPTDemodActions_los: public SWGObject { +public: + SWGAPTDemodActions_los(); + SWGAPTDemodActions_los(QString* json); + virtual ~SWGAPTDemodActions_los(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGAPTDemodActions_los* fromJson(QString &jsonString) override; + + QString* getSatelliteName(); + void setSatelliteName(QString* satellite_name); + + + virtual bool isSet() override; + +private: + QString* satellite_name; + bool m_satellite_name_isSet; + +}; + +} + +#endif /* SWGAPTDemodActions_los_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGAPTDemodSettings.cpp new file mode 100644 index 000000000..d3b974d63 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodSettings.cpp @@ -0,0 +1,597 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGAPTDemodSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGAPTDemodSettings::SWGAPTDemodSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGAPTDemodSettings::SWGAPTDemodSettings() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0.0f; + m_rf_bandwidth_isSet = false; + fm_deviation = 0; + m_fm_deviation_isSet = false; + crop_noise = 0; + m_crop_noise_isSet = false; + denoise = 0; + m_denoise_isSet = false; + linear_equalise = 0; + m_linear_equalise_isSet = false; + histogram_equalise = 0; + m_histogram_equalise_isSet = false; + precipitation_overlay = 0; + m_precipitation_overlay_isSet = false; + flip = 0; + m_flip_isSet = false; + channels = 0; + m_channels_isSet = false; + decode_enabled = 0; + m_decode_enabled_isSet = false; + auto_save = 0; + m_auto_save_isSet = false; + auto_save_path = nullptr; + m_auto_save_path_isSet = false; + auto_save_min_scan_lines = 0; + m_auto_save_min_scan_lines_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = nullptr; + m_title_isSet = false; + stream_index = 0; + m_stream_index_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = nullptr; + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +SWGAPTDemodSettings::~SWGAPTDemodSettings() { + this->cleanup(); +} + +void +SWGAPTDemodSettings::init() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0.0f; + m_rf_bandwidth_isSet = false; + fm_deviation = 0; + m_fm_deviation_isSet = false; + crop_noise = 0; + m_crop_noise_isSet = false; + denoise = 0; + m_denoise_isSet = false; + linear_equalise = 0; + m_linear_equalise_isSet = false; + histogram_equalise = 0; + m_histogram_equalise_isSet = false; + precipitation_overlay = 0; + m_precipitation_overlay_isSet = false; + flip = 0; + m_flip_isSet = false; + channels = 0; + m_channels_isSet = false; + decode_enabled = 0; + m_decode_enabled_isSet = false; + auto_save = 0; + m_auto_save_isSet = false; + auto_save_path = new QString(""); + m_auto_save_path_isSet = false; + auto_save_min_scan_lines = 0; + m_auto_save_min_scan_lines_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = new QString(""); + m_title_isSet = false; + stream_index = 0; + m_stream_index_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = new QString(""); + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +void +SWGAPTDemodSettings::cleanup() { + + + + + + + + + + + + + if(auto_save_path != nullptr) { + delete auto_save_path; + } + + + if(title != nullptr) { + delete title; + } + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + +} + +SWGAPTDemodSettings* +SWGAPTDemodSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGAPTDemodSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", ""); + + ::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", ""); + + ::SWGSDRangel::setValue(&fm_deviation, pJson["fmDeviation"], "qint32", ""); + + ::SWGSDRangel::setValue(&crop_noise, pJson["cropNoise"], "qint32", ""); + + ::SWGSDRangel::setValue(&denoise, pJson["denoise"], "qint32", ""); + + ::SWGSDRangel::setValue(&linear_equalise, pJson["linearEqualise"], "qint32", ""); + + ::SWGSDRangel::setValue(&histogram_equalise, pJson["histogramEqualise"], "qint32", ""); + + ::SWGSDRangel::setValue(&precipitation_overlay, pJson["precipitationOverlay"], "qint32", ""); + + ::SWGSDRangel::setValue(&flip, pJson["flip"], "qint32", ""); + + ::SWGSDRangel::setValue(&channels, pJson["channels"], "qint32", ""); + + ::SWGSDRangel::setValue(&decode_enabled, pJson["decodeEnabled"], "qint32", ""); + + ::SWGSDRangel::setValue(&auto_save, pJson["autoSave"], "qint32", ""); + + ::SWGSDRangel::setValue(&auto_save_path, pJson["autoSavePath"], "QString", "QString"); + + ::SWGSDRangel::setValue(&auto_save_min_scan_lines, pJson["autoSaveMinScanLines"], "qint32", ""); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", ""); + +} + +QString +SWGAPTDemodSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGAPTDemodSettings::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_input_frequency_offset_isSet){ + obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset)); + } + if(m_rf_bandwidth_isSet){ + obj->insert("rfBandwidth", QJsonValue(rf_bandwidth)); + } + if(m_fm_deviation_isSet){ + obj->insert("fmDeviation", QJsonValue(fm_deviation)); + } + if(m_crop_noise_isSet){ + obj->insert("cropNoise", QJsonValue(crop_noise)); + } + if(m_denoise_isSet){ + obj->insert("denoise", QJsonValue(denoise)); + } + if(m_linear_equalise_isSet){ + obj->insert("linearEqualise", QJsonValue(linear_equalise)); + } + if(m_histogram_equalise_isSet){ + obj->insert("histogramEqualise", QJsonValue(histogram_equalise)); + } + if(m_precipitation_overlay_isSet){ + obj->insert("precipitationOverlay", QJsonValue(precipitation_overlay)); + } + if(m_flip_isSet){ + obj->insert("flip", QJsonValue(flip)); + } + if(m_channels_isSet){ + obj->insert("channels", QJsonValue(channels)); + } + if(m_decode_enabled_isSet){ + obj->insert("decodeEnabled", QJsonValue(decode_enabled)); + } + if(m_auto_save_isSet){ + obj->insert("autoSave", QJsonValue(auto_save)); + } + if(auto_save_path != nullptr && *auto_save_path != QString("")){ + toJsonValue(QString("autoSavePath"), auto_save_path, obj, QString("QString")); + } + if(m_auto_save_min_scan_lines_isSet){ + obj->insert("autoSaveMinScanLines", QJsonValue(auto_save_min_scan_lines)); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(m_stream_index_isSet){ + obj->insert("streamIndex", QJsonValue(stream_index)); + } + if(m_use_reverse_api_isSet){ + obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); + } + if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ + toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString")); + } + if(m_reverse_api_port_isSet){ + obj->insert("reverseAPIPort", QJsonValue(reverse_api_port)); + } + if(m_reverse_api_device_index_isSet){ + obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index)); + } + if(m_reverse_api_channel_index_isSet){ + obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index)); + } + + return obj; +} + +qint64 +SWGAPTDemodSettings::getInputFrequencyOffset() { + return input_frequency_offset; +} +void +SWGAPTDemodSettings::setInputFrequencyOffset(qint64 input_frequency_offset) { + this->input_frequency_offset = input_frequency_offset; + this->m_input_frequency_offset_isSet = true; +} + +float +SWGAPTDemodSettings::getRfBandwidth() { + return rf_bandwidth; +} +void +SWGAPTDemodSettings::setRfBandwidth(float rf_bandwidth) { + this->rf_bandwidth = rf_bandwidth; + this->m_rf_bandwidth_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getFmDeviation() { + return fm_deviation; +} +void +SWGAPTDemodSettings::setFmDeviation(qint32 fm_deviation) { + this->fm_deviation = fm_deviation; + this->m_fm_deviation_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getCropNoise() { + return crop_noise; +} +void +SWGAPTDemodSettings::setCropNoise(qint32 crop_noise) { + this->crop_noise = crop_noise; + this->m_crop_noise_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getDenoise() { + return denoise; +} +void +SWGAPTDemodSettings::setDenoise(qint32 denoise) { + this->denoise = denoise; + this->m_denoise_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getLinearEqualise() { + return linear_equalise; +} +void +SWGAPTDemodSettings::setLinearEqualise(qint32 linear_equalise) { + this->linear_equalise = linear_equalise; + this->m_linear_equalise_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getHistogramEqualise() { + return histogram_equalise; +} +void +SWGAPTDemodSettings::setHistogramEqualise(qint32 histogram_equalise) { + this->histogram_equalise = histogram_equalise; + this->m_histogram_equalise_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getPrecipitationOverlay() { + return precipitation_overlay; +} +void +SWGAPTDemodSettings::setPrecipitationOverlay(qint32 precipitation_overlay) { + this->precipitation_overlay = precipitation_overlay; + this->m_precipitation_overlay_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getFlip() { + return flip; +} +void +SWGAPTDemodSettings::setFlip(qint32 flip) { + this->flip = flip; + this->m_flip_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getChannels() { + return channels; +} +void +SWGAPTDemodSettings::setChannels(qint32 channels) { + this->channels = channels; + this->m_channels_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getDecodeEnabled() { + return decode_enabled; +} +void +SWGAPTDemodSettings::setDecodeEnabled(qint32 decode_enabled) { + this->decode_enabled = decode_enabled; + this->m_decode_enabled_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getAutoSave() { + return auto_save; +} +void +SWGAPTDemodSettings::setAutoSave(qint32 auto_save) { + this->auto_save = auto_save; + this->m_auto_save_isSet = true; +} + +QString* +SWGAPTDemodSettings::getAutoSavePath() { + return auto_save_path; +} +void +SWGAPTDemodSettings::setAutoSavePath(QString* auto_save_path) { + this->auto_save_path = auto_save_path; + this->m_auto_save_path_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getAutoSaveMinScanLines() { + return auto_save_min_scan_lines; +} +void +SWGAPTDemodSettings::setAutoSaveMinScanLines(qint32 auto_save_min_scan_lines) { + this->auto_save_min_scan_lines = auto_save_min_scan_lines; + this->m_auto_save_min_scan_lines_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getRgbColor() { + return rgb_color; +} +void +SWGAPTDemodSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +QString* +SWGAPTDemodSettings::getTitle() { + return title; +} +void +SWGAPTDemodSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getStreamIndex() { + return stream_index; +} +void +SWGAPTDemodSettings::setStreamIndex(qint32 stream_index) { + this->stream_index = stream_index; + this->m_stream_index_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGAPTDemodSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGAPTDemodSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGAPTDemodSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGAPTDemodSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGAPTDemodSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGAPTDemodSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGAPTDemodSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + + +bool +SWGAPTDemodSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_input_frequency_offset_isSet){ + isObjectUpdated = true; break; + } + if(m_rf_bandwidth_isSet){ + isObjectUpdated = true; break; + } + if(m_fm_deviation_isSet){ + isObjectUpdated = true; break; + } + if(m_crop_noise_isSet){ + isObjectUpdated = true; break; + } + if(m_denoise_isSet){ + isObjectUpdated = true; break; + } + if(m_linear_equalise_isSet){ + isObjectUpdated = true; break; + } + if(m_histogram_equalise_isSet){ + isObjectUpdated = true; break; + } + if(m_precipitation_overlay_isSet){ + isObjectUpdated = true; break; + } + if(m_flip_isSet){ + isObjectUpdated = true; break; + } + if(m_channels_isSet){ + isObjectUpdated = true; break; + } + if(m_decode_enabled_isSet){ + isObjectUpdated = true; break; + } + if(m_auto_save_isSet){ + isObjectUpdated = true; break; + } + if(auto_save_path && *auto_save_path != QString("")){ + isObjectUpdated = true; break; + } + if(m_auto_save_min_scan_lines_isSet){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + isObjectUpdated = true; break; + } + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(m_stream_index_isSet){ + isObjectUpdated = true; break; + } + if(m_use_reverse_api_isSet){ + isObjectUpdated = true; break; + } + if(reverse_api_address && *reverse_api_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_reverse_api_port_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_device_index_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_channel_index_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGAPTDemodSettings.h b/swagger/sdrangel/code/qt5/client/SWGAPTDemodSettings.h new file mode 100644 index 000000000..f02a14bdc --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAPTDemodSettings.h @@ -0,0 +1,185 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGAPTDemodSettings.h + * + * APTDemod + */ + +#ifndef SWGAPTDemodSettings_H_ +#define SWGAPTDemodSettings_H_ + +#include + + +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGAPTDemodSettings: public SWGObject { +public: + SWGAPTDemodSettings(); + SWGAPTDemodSettings(QString* json); + virtual ~SWGAPTDemodSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGAPTDemodSettings* fromJson(QString &jsonString) override; + + qint64 getInputFrequencyOffset(); + void setInputFrequencyOffset(qint64 input_frequency_offset); + + float getRfBandwidth(); + void setRfBandwidth(float rf_bandwidth); + + qint32 getFmDeviation(); + void setFmDeviation(qint32 fm_deviation); + + qint32 getCropNoise(); + void setCropNoise(qint32 crop_noise); + + qint32 getDenoise(); + void setDenoise(qint32 denoise); + + qint32 getLinearEqualise(); + void setLinearEqualise(qint32 linear_equalise); + + qint32 getHistogramEqualise(); + void setHistogramEqualise(qint32 histogram_equalise); + + qint32 getPrecipitationOverlay(); + void setPrecipitationOverlay(qint32 precipitation_overlay); + + qint32 getFlip(); + void setFlip(qint32 flip); + + qint32 getChannels(); + void setChannels(qint32 channels); + + qint32 getDecodeEnabled(); + void setDecodeEnabled(qint32 decode_enabled); + + qint32 getAutoSave(); + void setAutoSave(qint32 auto_save); + + QString* getAutoSavePath(); + void setAutoSavePath(QString* auto_save_path); + + qint32 getAutoSaveMinScanLines(); + void setAutoSaveMinScanLines(qint32 auto_save_min_scan_lines); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + QString* getTitle(); + void setTitle(QString* title); + + qint32 getStreamIndex(); + void setStreamIndex(qint32 stream_index); + + qint32 getUseReverseApi(); + void setUseReverseApi(qint32 use_reverse_api); + + QString* getReverseApiAddress(); + void setReverseApiAddress(QString* reverse_api_address); + + qint32 getReverseApiPort(); + void setReverseApiPort(qint32 reverse_api_port); + + qint32 getReverseApiDeviceIndex(); + void setReverseApiDeviceIndex(qint32 reverse_api_device_index); + + qint32 getReverseApiChannelIndex(); + void setReverseApiChannelIndex(qint32 reverse_api_channel_index); + + + virtual bool isSet() override; + +private: + qint64 input_frequency_offset; + bool m_input_frequency_offset_isSet; + + float rf_bandwidth; + bool m_rf_bandwidth_isSet; + + qint32 fm_deviation; + bool m_fm_deviation_isSet; + + qint32 crop_noise; + bool m_crop_noise_isSet; + + qint32 denoise; + bool m_denoise_isSet; + + qint32 linear_equalise; + bool m_linear_equalise_isSet; + + qint32 histogram_equalise; + bool m_histogram_equalise_isSet; + + qint32 precipitation_overlay; + bool m_precipitation_overlay_isSet; + + qint32 flip; + bool m_flip_isSet; + + qint32 channels; + bool m_channels_isSet; + + qint32 decode_enabled; + bool m_decode_enabled_isSet; + + qint32 auto_save; + bool m_auto_save_isSet; + + QString* auto_save_path; + bool m_auto_save_path_isSet; + + qint32 auto_save_min_scan_lines; + bool m_auto_save_min_scan_lines_isSet; + + qint32 rgb_color; + bool m_rgb_color_isSet; + + QString* title; + bool m_title_isSet; + + qint32 stream_index; + bool m_stream_index_isSet; + + qint32 use_reverse_api; + bool m_use_reverse_api_isSet; + + QString* reverse_api_address; + bool m_reverse_api_address_isSet; + + qint32 reverse_api_port; + bool m_reverse_api_port_isSet; + + qint32 reverse_api_device_index; + bool m_reverse_api_device_index_isSet; + + qint32 reverse_api_channel_index; + bool m_reverse_api_channel_index_isSet; + +}; + +} + +#endif /* SWGAPTDemodSettings_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp b/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp index 6aa42d043..7893bbcaa 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp @@ -36,6 +36,8 @@ SWGChannelActions::SWGChannelActions() { m_originator_device_set_index_isSet = false; originator_channel_index = 0; m_originator_channel_index_isSet = false; + apt_demod_actions = nullptr; + m_apt_demod_actions_isSet = false; file_sink_actions = nullptr; m_file_sink_actions_isSet = false; file_source_actions = nullptr; @@ -62,6 +64,8 @@ SWGChannelActions::init() { m_originator_device_set_index_isSet = false; originator_channel_index = 0; m_originator_channel_index_isSet = false; + apt_demod_actions = new SWGAPTDemodActions(); + m_apt_demod_actions_isSet = false; file_sink_actions = new SWGFileSinkActions(); m_file_sink_actions_isSet = false; file_source_actions = new SWGFileSourceActions(); @@ -82,6 +86,9 @@ SWGChannelActions::cleanup() { + if(apt_demod_actions != nullptr) { + delete apt_demod_actions; + } if(file_sink_actions != nullptr) { delete file_sink_actions; } @@ -118,6 +125,8 @@ SWGChannelActions::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&originator_channel_index, pJson["originatorChannelIndex"], "qint32", ""); + ::SWGSDRangel::setValue(&apt_demod_actions, pJson["APTDemodActions"], "SWGAPTDemodActions", "SWGAPTDemodActions"); + ::SWGSDRangel::setValue(&file_sink_actions, pJson["FileSinkActions"], "SWGFileSinkActions", "SWGFileSinkActions"); ::SWGSDRangel::setValue(&file_source_actions, pJson["FileSourceActions"], "SWGFileSourceActions", "SWGFileSourceActions"); @@ -156,6 +165,9 @@ SWGChannelActions::asJsonObject() { if(m_originator_channel_index_isSet){ obj->insert("originatorChannelIndex", QJsonValue(originator_channel_index)); } + if((apt_demod_actions != nullptr) && (apt_demod_actions->isSet())){ + toJsonValue(QString("APTDemodActions"), apt_demod_actions, obj, QString("SWGAPTDemodActions")); + } if((file_sink_actions != nullptr) && (file_sink_actions->isSet())){ toJsonValue(QString("FileSinkActions"), file_sink_actions, obj, QString("SWGFileSinkActions")); } @@ -215,6 +227,16 @@ SWGChannelActions::setOriginatorChannelIndex(qint32 originator_channel_index) { this->m_originator_channel_index_isSet = true; } +SWGAPTDemodActions* +SWGChannelActions::getAptDemodActions() { + return apt_demod_actions; +} +void +SWGChannelActions::setAptDemodActions(SWGAPTDemodActions* apt_demod_actions) { + this->apt_demod_actions = apt_demod_actions; + this->m_apt_demod_actions_isSet = true; +} + SWGFileSinkActions* SWGChannelActions::getFileSinkActions() { return file_sink_actions; @@ -282,6 +304,9 @@ SWGChannelActions::isSet(){ if(m_originator_channel_index_isSet){ isObjectUpdated = true; break; } + if(apt_demod_actions && apt_demod_actions->isSet()){ + isObjectUpdated = true; break; + } if(file_sink_actions && file_sink_actions->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelActions.h b/swagger/sdrangel/code/qt5/client/SWGChannelActions.h index 8246babc4..04d8f2f5a 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelActions.h +++ b/swagger/sdrangel/code/qt5/client/SWGChannelActions.h @@ -22,6 +22,7 @@ #include +#include "SWGAPTDemodActions.h" #include "SWGFileSinkActions.h" #include "SWGFileSourceActions.h" #include "SWGIEEE_802_15_4_ModActions.h" @@ -59,6 +60,9 @@ public: qint32 getOriginatorChannelIndex(); void setOriginatorChannelIndex(qint32 originator_channel_index); + SWGAPTDemodActions* getAptDemodActions(); + void setAptDemodActions(SWGAPTDemodActions* apt_demod_actions); + SWGFileSinkActions* getFileSinkActions(); void setFileSinkActions(SWGFileSinkActions* file_sink_actions); @@ -90,6 +94,9 @@ private: qint32 originator_channel_index; bool m_originator_channel_index_isSet; + SWGAPTDemodActions* apt_demod_actions; + bool m_apt_demod_actions_isSet; + SWGFileSinkActions* file_sink_actions; bool m_file_sink_actions_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp index 1a2b5ee4c..e98496839 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp @@ -42,6 +42,8 @@ SWGChannelSettings::SWGChannelSettings() { m_am_demod_settings_isSet = false; am_mod_settings = nullptr; m_am_mod_settings_isSet = false; + apt_demod_settings = nullptr; + m_apt_demod_settings_isSet = false; atv_demod_settings = nullptr; m_atv_demod_settings_isSet = false; atv_mod_settings = nullptr; @@ -130,6 +132,8 @@ SWGChannelSettings::init() { m_am_demod_settings_isSet = false; am_mod_settings = new SWGAMModSettings(); m_am_mod_settings_isSet = false; + apt_demod_settings = new SWGAPTDemodSettings(); + m_apt_demod_settings_isSet = false; atv_demod_settings = new SWGATVDemodSettings(); m_atv_demod_settings_isSet = false; atv_mod_settings = new SWGATVModSettings(); @@ -215,6 +219,9 @@ SWGChannelSettings::cleanup() { if(am_mod_settings != nullptr) { delete am_mod_settings; } + if(apt_demod_settings != nullptr) { + delete apt_demod_settings; + } if(atv_demod_settings != nullptr) { delete atv_demod_settings; } @@ -341,6 +348,8 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&am_mod_settings, pJson["AMModSettings"], "SWGAMModSettings", "SWGAMModSettings"); + ::SWGSDRangel::setValue(&apt_demod_settings, pJson["APTDemodSettings"], "SWGAPTDemodSettings", "SWGAPTDemodSettings"); + ::SWGSDRangel::setValue(&atv_demod_settings, pJson["ATVDemodSettings"], "SWGATVDemodSettings", "SWGATVDemodSettings"); ::SWGSDRangel::setValue(&atv_mod_settings, pJson["ATVModSettings"], "SWGATVModSettings", "SWGATVModSettings"); @@ -444,6 +453,9 @@ SWGChannelSettings::asJsonObject() { if((am_mod_settings != nullptr) && (am_mod_settings->isSet())){ toJsonValue(QString("AMModSettings"), am_mod_settings, obj, QString("SWGAMModSettings")); } + if((apt_demod_settings != nullptr) && (apt_demod_settings->isSet())){ + toJsonValue(QString("APTDemodSettings"), apt_demod_settings, obj, QString("SWGAPTDemodSettings")); + } if((atv_demod_settings != nullptr) && (atv_demod_settings->isSet())){ toJsonValue(QString("ATVDemodSettings"), atv_demod_settings, obj, QString("SWGATVDemodSettings")); } @@ -617,6 +629,16 @@ SWGChannelSettings::setAmModSettings(SWGAMModSettings* am_mod_settings) { this->m_am_mod_settings_isSet = true; } +SWGAPTDemodSettings* +SWGChannelSettings::getAptDemodSettings() { + return apt_demod_settings; +} +void +SWGChannelSettings::setAptDemodSettings(SWGAPTDemodSettings* apt_demod_settings) { + this->apt_demod_settings = apt_demod_settings; + this->m_apt_demod_settings_isSet = true; +} + SWGATVDemodSettings* SWGChannelSettings::getAtvDemodSettings() { return atv_demod_settings; @@ -973,6 +995,9 @@ SWGChannelSettings::isSet(){ if(am_mod_settings && am_mod_settings->isSet()){ isObjectUpdated = true; break; } + if(apt_demod_settings && apt_demod_settings->isSet()){ + isObjectUpdated = true; break; + } if(atv_demod_settings && atv_demod_settings->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h index 1dde09d7d..d60aafc36 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h @@ -25,6 +25,7 @@ #include "SWGADSBDemodSettings.h" #include "SWGAMDemodSettings.h" #include "SWGAMModSettings.h" +#include "SWGAPTDemodSettings.h" #include "SWGATVDemodSettings.h" #include "SWGATVModSettings.h" #include "SWGBFMDemodSettings.h" @@ -99,6 +100,9 @@ public: SWGAMModSettings* getAmModSettings(); void setAmModSettings(SWGAMModSettings* am_mod_settings); + SWGAPTDemodSettings* getAptDemodSettings(); + void setAptDemodSettings(SWGAPTDemodSettings* apt_demod_settings); + SWGATVDemodSettings* getAtvDemodSettings(); void setAtvDemodSettings(SWGATVDemodSettings* atv_demod_settings); @@ -223,6 +227,9 @@ private: SWGAMModSettings* am_mod_settings; bool m_am_mod_settings_isSet; + SWGAPTDemodSettings* apt_demod_settings; + bool m_apt_demod_settings_isSet; + SWGATVDemodSettings* atv_demod_settings; bool m_atv_demod_settings_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp index fecafd5bd..a7b1fd4a4 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp @@ -46,6 +46,8 @@ SWGFeatureSettings::SWGFeatureSettings() { m_map_settings_isSet = false; rig_ctl_server_settings = nullptr; m_rig_ctl_server_settings_isSet = false; + satellite_tracker_settings = nullptr; + m_satellite_tracker_settings_isSet = false; star_tracker_settings = nullptr; m_star_tracker_settings_isSet = false; simple_ptt_settings = nullptr; @@ -78,6 +80,8 @@ SWGFeatureSettings::init() { m_map_settings_isSet = false; rig_ctl_server_settings = new SWGRigCtlServerSettings(); m_rig_ctl_server_settings_isSet = false; + satellite_tracker_settings = new SWGSatelliteTrackerSettings(); + m_satellite_tracker_settings_isSet = false; star_tracker_settings = new SWGStarTrackerSettings(); m_star_tracker_settings_isSet = false; simple_ptt_settings = new SWGSimplePTTSettings(); @@ -111,6 +115,9 @@ SWGFeatureSettings::cleanup() { if(rig_ctl_server_settings != nullptr) { delete rig_ctl_server_settings; } + if(satellite_tracker_settings != nullptr) { + delete satellite_tracker_settings; + } if(star_tracker_settings != nullptr) { delete star_tracker_settings; } @@ -151,6 +158,8 @@ SWGFeatureSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&rig_ctl_server_settings, pJson["RigCtlServerSettings"], "SWGRigCtlServerSettings", "SWGRigCtlServerSettings"); + ::SWGSDRangel::setValue(&satellite_tracker_settings, pJson["SatelliteTrackerSettings"], "SWGSatelliteTrackerSettings", "SWGSatelliteTrackerSettings"); + ::SWGSDRangel::setValue(&star_tracker_settings, pJson["StarTrackerSettings"], "SWGStarTrackerSettings", "SWGStarTrackerSettings"); ::SWGSDRangel::setValue(&simple_ptt_settings, pJson["SimplePTTSettings"], "SWGSimplePTTSettings", "SWGSimplePTTSettings"); @@ -200,6 +209,9 @@ SWGFeatureSettings::asJsonObject() { if((rig_ctl_server_settings != nullptr) && (rig_ctl_server_settings->isSet())){ toJsonValue(QString("RigCtlServerSettings"), rig_ctl_server_settings, obj, QString("SWGRigCtlServerSettings")); } + if((satellite_tracker_settings != nullptr) && (satellite_tracker_settings->isSet())){ + toJsonValue(QString("SatelliteTrackerSettings"), satellite_tracker_settings, obj, QString("SWGSatelliteTrackerSettings")); + } if((star_tracker_settings != nullptr) && (star_tracker_settings->isSet())){ toJsonValue(QString("StarTrackerSettings"), star_tracker_settings, obj, QString("SWGStarTrackerSettings")); } @@ -303,6 +315,16 @@ SWGFeatureSettings::setRigCtlServerSettings(SWGRigCtlServerSettings* rig_ctl_ser this->m_rig_ctl_server_settings_isSet = true; } +SWGSatelliteTrackerSettings* +SWGFeatureSettings::getSatelliteTrackerSettings() { + return satellite_tracker_settings; +} +void +SWGFeatureSettings::setSatelliteTrackerSettings(SWGSatelliteTrackerSettings* satellite_tracker_settings) { + this->satellite_tracker_settings = satellite_tracker_settings; + this->m_satellite_tracker_settings_isSet = true; +} + SWGStarTrackerSettings* SWGFeatureSettings::getStarTrackerSettings() { return star_tracker_settings; @@ -365,6 +387,9 @@ SWGFeatureSettings::isSet(){ if(rig_ctl_server_settings && rig_ctl_server_settings->isSet()){ isObjectUpdated = true; break; } + if(satellite_tracker_settings && satellite_tracker_settings->isSet()){ + isObjectUpdated = true; break; + } if(star_tracker_settings && star_tracker_settings->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h index 36858b501..b746d3c67 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h @@ -28,6 +28,7 @@ #include "SWGGS232ControllerSettings.h" #include "SWGMapSettings.h" #include "SWGRigCtlServerSettings.h" +#include "SWGSatelliteTrackerSettings.h" #include "SWGSimplePTTSettings.h" #include "SWGStarTrackerSettings.h" #include "SWGVORLocalizerSettings.h" @@ -78,6 +79,9 @@ public: SWGRigCtlServerSettings* getRigCtlServerSettings(); void setRigCtlServerSettings(SWGRigCtlServerSettings* rig_ctl_server_settings); + SWGSatelliteTrackerSettings* getSatelliteTrackerSettings(); + void setSatelliteTrackerSettings(SWGSatelliteTrackerSettings* satellite_tracker_settings); + SWGStarTrackerSettings* getStarTrackerSettings(); void setStarTrackerSettings(SWGStarTrackerSettings* star_tracker_settings); @@ -118,6 +122,9 @@ private: SWGRigCtlServerSettings* rig_ctl_server_settings; bool m_rig_ctl_server_settings_isSet; + SWGSatelliteTrackerSettings* satellite_tracker_settings; + bool m_satellite_tracker_settings_isSet; + SWGStarTrackerSettings* star_tracker_settings; bool m_star_tracker_settings_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp index 15394e4d9..cab3b0ed5 100644 --- a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.cpp @@ -44,6 +44,14 @@ SWGGS232ControllerSettings::SWGGS232ControllerSettings() { m_azimuth_offset_isSet = false; elevation_offset = 0; m_elevation_offset_isSet = false; + azimuth_min = 0; + m_azimuth_min_isSet = false; + azimuth_max = 0; + m_azimuth_max_isSet = false; + elevation_min = 0; + m_elevation_min_isSet = false; + elevation_max = 0; + m_elevation_max_isSet = false; title = nullptr; m_title_isSet = false; rgb_color = 0; @@ -82,6 +90,14 @@ SWGGS232ControllerSettings::init() { m_azimuth_offset_isSet = false; elevation_offset = 0; m_elevation_offset_isSet = false; + azimuth_min = 0; + m_azimuth_min_isSet = false; + azimuth_max = 0; + m_azimuth_max_isSet = false; + elevation_min = 0; + m_elevation_min_isSet = false; + elevation_max = 0; + m_elevation_max_isSet = false; title = new QString(""); m_title_isSet = false; rgb_color = 0; @@ -112,6 +128,10 @@ SWGGS232ControllerSettings::cleanup() { } + + + + if(title != nullptr) { delete title; } @@ -152,6 +172,14 @@ SWGGS232ControllerSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&elevation_offset, pJson["elevationOffset"], "qint32", ""); + ::SWGSDRangel::setValue(&azimuth_min, pJson["azimuthMin"], "qint32", ""); + + ::SWGSDRangel::setValue(&azimuth_max, pJson["azimuthMax"], "qint32", ""); + + ::SWGSDRangel::setValue(&elevation_min, pJson["elevationMin"], "qint32", ""); + + ::SWGSDRangel::setValue(&elevation_max, pJson["elevationMax"], "qint32", ""); + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); @@ -206,6 +234,18 @@ SWGGS232ControllerSettings::asJsonObject() { if(m_elevation_offset_isSet){ obj->insert("elevationOffset", QJsonValue(elevation_offset)); } + if(m_azimuth_min_isSet){ + obj->insert("azimuthMin", QJsonValue(azimuth_min)); + } + if(m_azimuth_max_isSet){ + obj->insert("azimuthMax", QJsonValue(azimuth_max)); + } + if(m_elevation_min_isSet){ + obj->insert("elevationMin", QJsonValue(elevation_min)); + } + if(m_elevation_max_isSet){ + obj->insert("elevationMax", QJsonValue(elevation_max)); + } if(title != nullptr && *title != QString("")){ toJsonValue(QString("title"), title, obj, QString("QString")); } @@ -311,6 +351,46 @@ SWGGS232ControllerSettings::setElevationOffset(qint32 elevation_offset) { this->m_elevation_offset_isSet = true; } +qint32 +SWGGS232ControllerSettings::getAzimuthMin() { + return azimuth_min; +} +void +SWGGS232ControllerSettings::setAzimuthMin(qint32 azimuth_min) { + this->azimuth_min = azimuth_min; + this->m_azimuth_min_isSet = true; +} + +qint32 +SWGGS232ControllerSettings::getAzimuthMax() { + return azimuth_max; +} +void +SWGGS232ControllerSettings::setAzimuthMax(qint32 azimuth_max) { + this->azimuth_max = azimuth_max; + this->m_azimuth_max_isSet = true; +} + +qint32 +SWGGS232ControllerSettings::getElevationMin() { + return elevation_min; +} +void +SWGGS232ControllerSettings::setElevationMin(qint32 elevation_min) { + this->elevation_min = elevation_min; + this->m_elevation_min_isSet = true; +} + +qint32 +SWGGS232ControllerSettings::getElevationMax() { + return elevation_max; +} +void +SWGGS232ControllerSettings::setElevationMax(qint32 elevation_max) { + this->elevation_max = elevation_max; + this->m_elevation_max_isSet = true; +} + QString* SWGGS232ControllerSettings::getTitle() { return title; @@ -410,6 +490,18 @@ SWGGS232ControllerSettings::isSet(){ if(m_elevation_offset_isSet){ isObjectUpdated = true; break; } + if(m_azimuth_min_isSet){ + isObjectUpdated = true; break; + } + if(m_azimuth_max_isSet){ + isObjectUpdated = true; break; + } + if(m_elevation_min_isSet){ + isObjectUpdated = true; break; + } + if(m_elevation_max_isSet){ + isObjectUpdated = true; break; + } if(title && *title != QString("")){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h index 1a662bf9b..689936b02 100644 --- a/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGGS232ControllerSettings.h @@ -66,6 +66,18 @@ public: qint32 getElevationOffset(); void setElevationOffset(qint32 elevation_offset); + qint32 getAzimuthMin(); + void setAzimuthMin(qint32 azimuth_min); + + qint32 getAzimuthMax(); + void setAzimuthMax(qint32 azimuth_max); + + qint32 getElevationMin(); + void setElevationMin(qint32 elevation_min); + + qint32 getElevationMax(); + void setElevationMax(qint32 elevation_max); + QString* getTitle(); void setTitle(QString* title); @@ -115,6 +127,18 @@ private: qint32 elevation_offset; bool m_elevation_offset_isSet; + qint32 azimuth_min; + bool m_azimuth_min_isSet; + + qint32 azimuth_max; + bool m_azimuth_max_isSet; + + qint32 elevation_min; + bool m_elevation_min_isSet; + + qint32 elevation_max; + bool m_elevation_max_isSet; + QString* title; bool m_title_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGLRPTDemodSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGLRPTDemodSettings.cpp new file mode 100644 index 000000000..b1acba920 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGLRPTDemodSettings.cpp @@ -0,0 +1,597 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGLRPTDemodSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGLRPTDemodSettings::SWGLRPTDemodSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGLRPTDemodSettings::SWGLRPTDemodSettings() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0.0f; + m_rf_bandwidth_isSet = false; + fm_deviation = 0; + m_fm_deviation_isSet = false; + crop_noise = 0; + m_crop_noise_isSet = false; + denoise = 0; + m_denoise_isSet = false; + linear_equalise = 0; + m_linear_equalise_isSet = false; + histogram_equalise = 0; + m_histogram_equalise_isSet = false; + precipitation_overlay = 0; + m_precipitation_overlay_isSet = false; + flip = 0; + m_flip_isSet = false; + channels = 0; + m_channels_isSet = false; + decode_enabled = 0; + m_decode_enabled_isSet = false; + auto_save = 0; + m_auto_save_isSet = false; + auto_save_path = nullptr; + m_auto_save_path_isSet = false; + auto_save_min_scan_lines = 0; + m_auto_save_min_scan_lines_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = nullptr; + m_title_isSet = false; + stream_index = 0; + m_stream_index_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = nullptr; + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +SWGLRPTDemodSettings::~SWGLRPTDemodSettings() { + this->cleanup(); +} + +void +SWGLRPTDemodSettings::init() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0.0f; + m_rf_bandwidth_isSet = false; + fm_deviation = 0; + m_fm_deviation_isSet = false; + crop_noise = 0; + m_crop_noise_isSet = false; + denoise = 0; + m_denoise_isSet = false; + linear_equalise = 0; + m_linear_equalise_isSet = false; + histogram_equalise = 0; + m_histogram_equalise_isSet = false; + precipitation_overlay = 0; + m_precipitation_overlay_isSet = false; + flip = 0; + m_flip_isSet = false; + channels = 0; + m_channels_isSet = false; + decode_enabled = 0; + m_decode_enabled_isSet = false; + auto_save = 0; + m_auto_save_isSet = false; + auto_save_path = new QString(""); + m_auto_save_path_isSet = false; + auto_save_min_scan_lines = 0; + m_auto_save_min_scan_lines_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = new QString(""); + m_title_isSet = false; + stream_index = 0; + m_stream_index_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = new QString(""); + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +void +SWGLRPTDemodSettings::cleanup() { + + + + + + + + + + + + + if(auto_save_path != nullptr) { + delete auto_save_path; + } + + + if(title != nullptr) { + delete title; + } + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + +} + +SWGLRPTDemodSettings* +SWGLRPTDemodSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGLRPTDemodSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", ""); + + ::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", ""); + + ::SWGSDRangel::setValue(&fm_deviation, pJson["fmDeviation"], "qint32", ""); + + ::SWGSDRangel::setValue(&crop_noise, pJson["cropNoise"], "qint32", ""); + + ::SWGSDRangel::setValue(&denoise, pJson["denoise"], "qint32", ""); + + ::SWGSDRangel::setValue(&linear_equalise, pJson["linearEqualise"], "qint32", ""); + + ::SWGSDRangel::setValue(&histogram_equalise, pJson["histogramEqualise"], "qint32", ""); + + ::SWGSDRangel::setValue(&precipitation_overlay, pJson["precipitationOverlay"], "qint32", ""); + + ::SWGSDRangel::setValue(&flip, pJson["flip"], "qint32", ""); + + ::SWGSDRangel::setValue(&channels, pJson["channels"], "qint32", ""); + + ::SWGSDRangel::setValue(&decode_enabled, pJson["decodeEnabled"], "qint32", ""); + + ::SWGSDRangel::setValue(&auto_save, pJson["autoSave"], "qint32", ""); + + ::SWGSDRangel::setValue(&auto_save_path, pJson["autoSavePath"], "QString", "QString"); + + ::SWGSDRangel::setValue(&auto_save_min_scan_lines, pJson["autoSaveMinScanLines"], "qint32", ""); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", ""); + +} + +QString +SWGLRPTDemodSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGLRPTDemodSettings::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_input_frequency_offset_isSet){ + obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset)); + } + if(m_rf_bandwidth_isSet){ + obj->insert("rfBandwidth", QJsonValue(rf_bandwidth)); + } + if(m_fm_deviation_isSet){ + obj->insert("fmDeviation", QJsonValue(fm_deviation)); + } + if(m_crop_noise_isSet){ + obj->insert("cropNoise", QJsonValue(crop_noise)); + } + if(m_denoise_isSet){ + obj->insert("denoise", QJsonValue(denoise)); + } + if(m_linear_equalise_isSet){ + obj->insert("linearEqualise", QJsonValue(linear_equalise)); + } + if(m_histogram_equalise_isSet){ + obj->insert("histogramEqualise", QJsonValue(histogram_equalise)); + } + if(m_precipitation_overlay_isSet){ + obj->insert("precipitationOverlay", QJsonValue(precipitation_overlay)); + } + if(m_flip_isSet){ + obj->insert("flip", QJsonValue(flip)); + } + if(m_channels_isSet){ + obj->insert("channels", QJsonValue(channels)); + } + if(m_decode_enabled_isSet){ + obj->insert("decodeEnabled", QJsonValue(decode_enabled)); + } + if(m_auto_save_isSet){ + obj->insert("autoSave", QJsonValue(auto_save)); + } + if(auto_save_path != nullptr && *auto_save_path != QString("")){ + toJsonValue(QString("autoSavePath"), auto_save_path, obj, QString("QString")); + } + if(m_auto_save_min_scan_lines_isSet){ + obj->insert("autoSaveMinScanLines", QJsonValue(auto_save_min_scan_lines)); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(m_stream_index_isSet){ + obj->insert("streamIndex", QJsonValue(stream_index)); + } + if(m_use_reverse_api_isSet){ + obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); + } + if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ + toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString")); + } + if(m_reverse_api_port_isSet){ + obj->insert("reverseAPIPort", QJsonValue(reverse_api_port)); + } + if(m_reverse_api_device_index_isSet){ + obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index)); + } + if(m_reverse_api_channel_index_isSet){ + obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index)); + } + + return obj; +} + +qint64 +SWGLRPTDemodSettings::getInputFrequencyOffset() { + return input_frequency_offset; +} +void +SWGLRPTDemodSettings::setInputFrequencyOffset(qint64 input_frequency_offset) { + this->input_frequency_offset = input_frequency_offset; + this->m_input_frequency_offset_isSet = true; +} + +float +SWGLRPTDemodSettings::getRfBandwidth() { + return rf_bandwidth; +} +void +SWGLRPTDemodSettings::setRfBandwidth(float rf_bandwidth) { + this->rf_bandwidth = rf_bandwidth; + this->m_rf_bandwidth_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getFmDeviation() { + return fm_deviation; +} +void +SWGLRPTDemodSettings::setFmDeviation(qint32 fm_deviation) { + this->fm_deviation = fm_deviation; + this->m_fm_deviation_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getCropNoise() { + return crop_noise; +} +void +SWGLRPTDemodSettings::setCropNoise(qint32 crop_noise) { + this->crop_noise = crop_noise; + this->m_crop_noise_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getDenoise() { + return denoise; +} +void +SWGLRPTDemodSettings::setDenoise(qint32 denoise) { + this->denoise = denoise; + this->m_denoise_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getLinearEqualise() { + return linear_equalise; +} +void +SWGLRPTDemodSettings::setLinearEqualise(qint32 linear_equalise) { + this->linear_equalise = linear_equalise; + this->m_linear_equalise_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getHistogramEqualise() { + return histogram_equalise; +} +void +SWGLRPTDemodSettings::setHistogramEqualise(qint32 histogram_equalise) { + this->histogram_equalise = histogram_equalise; + this->m_histogram_equalise_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getPrecipitationOverlay() { + return precipitation_overlay; +} +void +SWGLRPTDemodSettings::setPrecipitationOverlay(qint32 precipitation_overlay) { + this->precipitation_overlay = precipitation_overlay; + this->m_precipitation_overlay_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getFlip() { + return flip; +} +void +SWGLRPTDemodSettings::setFlip(qint32 flip) { + this->flip = flip; + this->m_flip_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getChannels() { + return channels; +} +void +SWGLRPTDemodSettings::setChannels(qint32 channels) { + this->channels = channels; + this->m_channels_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getDecodeEnabled() { + return decode_enabled; +} +void +SWGLRPTDemodSettings::setDecodeEnabled(qint32 decode_enabled) { + this->decode_enabled = decode_enabled; + this->m_decode_enabled_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getAutoSave() { + return auto_save; +} +void +SWGLRPTDemodSettings::setAutoSave(qint32 auto_save) { + this->auto_save = auto_save; + this->m_auto_save_isSet = true; +} + +QString* +SWGLRPTDemodSettings::getAutoSavePath() { + return auto_save_path; +} +void +SWGLRPTDemodSettings::setAutoSavePath(QString* auto_save_path) { + this->auto_save_path = auto_save_path; + this->m_auto_save_path_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getAutoSaveMinScanLines() { + return auto_save_min_scan_lines; +} +void +SWGLRPTDemodSettings::setAutoSaveMinScanLines(qint32 auto_save_min_scan_lines) { + this->auto_save_min_scan_lines = auto_save_min_scan_lines; + this->m_auto_save_min_scan_lines_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getRgbColor() { + return rgb_color; +} +void +SWGLRPTDemodSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +QString* +SWGLRPTDemodSettings::getTitle() { + return title; +} +void +SWGLRPTDemodSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getStreamIndex() { + return stream_index; +} +void +SWGLRPTDemodSettings::setStreamIndex(qint32 stream_index) { + this->stream_index = stream_index; + this->m_stream_index_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGLRPTDemodSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGLRPTDemodSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGLRPTDemodSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGLRPTDemodSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGLRPTDemodSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGLRPTDemodSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGLRPTDemodSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + + +bool +SWGLRPTDemodSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_input_frequency_offset_isSet){ + isObjectUpdated = true; break; + } + if(m_rf_bandwidth_isSet){ + isObjectUpdated = true; break; + } + if(m_fm_deviation_isSet){ + isObjectUpdated = true; break; + } + if(m_crop_noise_isSet){ + isObjectUpdated = true; break; + } + if(m_denoise_isSet){ + isObjectUpdated = true; break; + } + if(m_linear_equalise_isSet){ + isObjectUpdated = true; break; + } + if(m_histogram_equalise_isSet){ + isObjectUpdated = true; break; + } + if(m_precipitation_overlay_isSet){ + isObjectUpdated = true; break; + } + if(m_flip_isSet){ + isObjectUpdated = true; break; + } + if(m_channels_isSet){ + isObjectUpdated = true; break; + } + if(m_decode_enabled_isSet){ + isObjectUpdated = true; break; + } + if(m_auto_save_isSet){ + isObjectUpdated = true; break; + } + if(auto_save_path && *auto_save_path != QString("")){ + isObjectUpdated = true; break; + } + if(m_auto_save_min_scan_lines_isSet){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + isObjectUpdated = true; break; + } + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(m_stream_index_isSet){ + isObjectUpdated = true; break; + } + if(m_use_reverse_api_isSet){ + isObjectUpdated = true; break; + } + if(reverse_api_address && *reverse_api_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_reverse_api_port_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_device_index_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_channel_index_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGLRPTDemodSettings.h b/swagger/sdrangel/code/qt5/client/SWGLRPTDemodSettings.h new file mode 100644 index 000000000..474759372 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGLRPTDemodSettings.h @@ -0,0 +1,185 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGLRPTDemodSettings.h + * + * LRPTDemod + */ + +#ifndef SWGLRPTDemodSettings_H_ +#define SWGLRPTDemodSettings_H_ + +#include + + +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGLRPTDemodSettings: public SWGObject { +public: + SWGLRPTDemodSettings(); + SWGLRPTDemodSettings(QString* json); + virtual ~SWGLRPTDemodSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGLRPTDemodSettings* fromJson(QString &jsonString) override; + + qint64 getInputFrequencyOffset(); + void setInputFrequencyOffset(qint64 input_frequency_offset); + + float getRfBandwidth(); + void setRfBandwidth(float rf_bandwidth); + + qint32 getFmDeviation(); + void setFmDeviation(qint32 fm_deviation); + + qint32 getCropNoise(); + void setCropNoise(qint32 crop_noise); + + qint32 getDenoise(); + void setDenoise(qint32 denoise); + + qint32 getLinearEqualise(); + void setLinearEqualise(qint32 linear_equalise); + + qint32 getHistogramEqualise(); + void setHistogramEqualise(qint32 histogram_equalise); + + qint32 getPrecipitationOverlay(); + void setPrecipitationOverlay(qint32 precipitation_overlay); + + qint32 getFlip(); + void setFlip(qint32 flip); + + qint32 getChannels(); + void setChannels(qint32 channels); + + qint32 getDecodeEnabled(); + void setDecodeEnabled(qint32 decode_enabled); + + qint32 getAutoSave(); + void setAutoSave(qint32 auto_save); + + QString* getAutoSavePath(); + void setAutoSavePath(QString* auto_save_path); + + qint32 getAutoSaveMinScanLines(); + void setAutoSaveMinScanLines(qint32 auto_save_min_scan_lines); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + QString* getTitle(); + void setTitle(QString* title); + + qint32 getStreamIndex(); + void setStreamIndex(qint32 stream_index); + + qint32 getUseReverseApi(); + void setUseReverseApi(qint32 use_reverse_api); + + QString* getReverseApiAddress(); + void setReverseApiAddress(QString* reverse_api_address); + + qint32 getReverseApiPort(); + void setReverseApiPort(qint32 reverse_api_port); + + qint32 getReverseApiDeviceIndex(); + void setReverseApiDeviceIndex(qint32 reverse_api_device_index); + + qint32 getReverseApiChannelIndex(); + void setReverseApiChannelIndex(qint32 reverse_api_channel_index); + + + virtual bool isSet() override; + +private: + qint64 input_frequency_offset; + bool m_input_frequency_offset_isSet; + + float rf_bandwidth; + bool m_rf_bandwidth_isSet; + + qint32 fm_deviation; + bool m_fm_deviation_isSet; + + qint32 crop_noise; + bool m_crop_noise_isSet; + + qint32 denoise; + bool m_denoise_isSet; + + qint32 linear_equalise; + bool m_linear_equalise_isSet; + + qint32 histogram_equalise; + bool m_histogram_equalise_isSet; + + qint32 precipitation_overlay; + bool m_precipitation_overlay_isSet; + + qint32 flip; + bool m_flip_isSet; + + qint32 channels; + bool m_channels_isSet; + + qint32 decode_enabled; + bool m_decode_enabled_isSet; + + qint32 auto_save; + bool m_auto_save_isSet; + + QString* auto_save_path; + bool m_auto_save_path_isSet; + + qint32 auto_save_min_scan_lines; + bool m_auto_save_min_scan_lines_isSet; + + qint32 rgb_color; + bool m_rgb_color_isSet; + + QString* title; + bool m_title_isSet; + + qint32 stream_index; + bool m_stream_index_isSet; + + qint32 use_reverse_api; + bool m_use_reverse_api_isSet; + + QString* reverse_api_address; + bool m_reverse_api_address_isSet; + + qint32 reverse_api_port; + bool m_reverse_api_port_isSet; + + qint32 reverse_api_device_index; + bool m_reverse_api_device_index_isSet; + + qint32 reverse_api_channel_index; + bool m_reverse_api_channel_index_isSet; + +}; + +} + +#endif /* SWGLRPTDemodSettings_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGMapCoordinate.cpp b/swagger/sdrangel/code/qt5/client/SWGMapCoordinate.cpp new file mode 100644 index 000000000..d63f5f0c5 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGMapCoordinate.cpp @@ -0,0 +1,154 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGMapCoordinate.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGMapCoordinate::SWGMapCoordinate(QString* json) { + init(); + this->fromJson(*json); +} + +SWGMapCoordinate::SWGMapCoordinate() { + latitude = 0.0f; + m_latitude_isSet = false; + longitude = 0.0f; + m_longitude_isSet = false; + altitude = 0.0f; + m_altitude_isSet = false; +} + +SWGMapCoordinate::~SWGMapCoordinate() { + this->cleanup(); +} + +void +SWGMapCoordinate::init() { + latitude = 0.0f; + m_latitude_isSet = false; + longitude = 0.0f; + m_longitude_isSet = false; + altitude = 0.0f; + m_altitude_isSet = false; +} + +void +SWGMapCoordinate::cleanup() { + + + +} + +SWGMapCoordinate* +SWGMapCoordinate::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGMapCoordinate::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&latitude, pJson["latitude"], "float", ""); + + ::SWGSDRangel::setValue(&longitude, pJson["longitude"], "float", ""); + + ::SWGSDRangel::setValue(&altitude, pJson["altitude"], "float", ""); + +} + +QString +SWGMapCoordinate::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGMapCoordinate::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_latitude_isSet){ + obj->insert("latitude", QJsonValue(latitude)); + } + if(m_longitude_isSet){ + obj->insert("longitude", QJsonValue(longitude)); + } + if(m_altitude_isSet){ + obj->insert("altitude", QJsonValue(altitude)); + } + + return obj; +} + +float +SWGMapCoordinate::getLatitude() { + return latitude; +} +void +SWGMapCoordinate::setLatitude(float latitude) { + this->latitude = latitude; + this->m_latitude_isSet = true; +} + +float +SWGMapCoordinate::getLongitude() { + return longitude; +} +void +SWGMapCoordinate::setLongitude(float longitude) { + this->longitude = longitude; + this->m_longitude_isSet = true; +} + +float +SWGMapCoordinate::getAltitude() { + return altitude; +} +void +SWGMapCoordinate::setAltitude(float altitude) { + this->altitude = altitude; + this->m_altitude_isSet = true; +} + + +bool +SWGMapCoordinate::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_latitude_isSet){ + isObjectUpdated = true; break; + } + if(m_longitude_isSet){ + isObjectUpdated = true; break; + } + if(m_altitude_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGMapCoordinate.h b/swagger/sdrangel/code/qt5/client/SWGMapCoordinate.h new file mode 100644 index 000000000..0388aa99d --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGMapCoordinate.h @@ -0,0 +1,70 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGMapCoordinate.h + * + * A map coordinate + */ + +#ifndef SWGMapCoordinate_H_ +#define SWGMapCoordinate_H_ + +#include + + + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGMapCoordinate: public SWGObject { +public: + SWGMapCoordinate(); + SWGMapCoordinate(QString* json); + virtual ~SWGMapCoordinate(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGMapCoordinate* fromJson(QString &jsonString) override; + + float getLatitude(); + void setLatitude(float latitude); + + float getLongitude(); + void setLongitude(float longitude); + + float getAltitude(); + void setAltitude(float altitude); + + + virtual bool isSet() override; + +private: + float latitude; + bool m_latitude_isSet; + + float longitude; + bool m_longitude_isSet; + + float altitude; + bool m_altitude_isSet; + +}; + +} + +#endif /* SWGMapCoordinate_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp b/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp index 901774d61..ca5850335 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem.cpp @@ -44,6 +44,10 @@ SWGMapItem::SWGMapItem() { m_longitude_isSet = false; altitude = 0.0f; m_altitude_isSet = false; + track = nullptr; + m_track_isSet = false; + predicted_track = nullptr; + m_predicted_track_isSet = false; } SWGMapItem::~SWGMapItem() { @@ -68,6 +72,10 @@ SWGMapItem::init() { m_longitude_isSet = false; altitude = 0.0f; m_altitude_isSet = false; + track = new QList(); + m_track_isSet = false; + predicted_track = new QList(); + m_predicted_track_isSet = false; } void @@ -86,6 +94,20 @@ SWGMapItem::cleanup() { + if(track != nullptr) { + auto arr = track; + for(auto o: *arr) { + delete o; + } + delete track; + } + if(predicted_track != nullptr) { + auto arr = predicted_track; + for(auto o: *arr) { + delete o; + } + delete predicted_track; + } } SWGMapItem* @@ -115,6 +137,10 @@ SWGMapItem::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&altitude, pJson["altitude"], "float", ""); + + ::SWGSDRangel::setValue(&track, pJson["track"], "QList", "SWGMapCoordinate"); + + ::SWGSDRangel::setValue(&predicted_track, pJson["predictedTrack"], "QList", "SWGMapCoordinate"); } QString @@ -155,6 +181,12 @@ SWGMapItem::asJsonObject() { if(m_altitude_isSet){ obj->insert("altitude", QJsonValue(altitude)); } + if(track && track->size() > 0){ + toJsonArray((QList*)track, obj, "track", "SWGMapCoordinate"); + } + if(predicted_track && predicted_track->size() > 0){ + toJsonArray((QList*)predicted_track, obj, "predictedTrack", "SWGMapCoordinate"); + } return obj; } @@ -239,6 +271,26 @@ SWGMapItem::setAltitude(float altitude) { this->m_altitude_isSet = true; } +QList* +SWGMapItem::getTrack() { + return track; +} +void +SWGMapItem::setTrack(QList* track) { + this->track = track; + this->m_track_isSet = true; +} + +QList* +SWGMapItem::getPredictedTrack() { + return predicted_track; +} +void +SWGMapItem::setPredictedTrack(QList* predicted_track) { + this->predicted_track = predicted_track; + this->m_predicted_track_isSet = true; +} + bool SWGMapItem::isSet(){ @@ -268,6 +320,12 @@ SWGMapItem::isSet(){ if(m_altitude_isSet){ isObjectUpdated = true; break; } + if(track && (track->size() > 0)){ + isObjectUpdated = true; break; + } + if(predicted_track && (predicted_track->size() > 0)){ + isObjectUpdated = true; break; + } }while(false); return isObjectUpdated; } diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem.h b/swagger/sdrangel/code/qt5/client/SWGMapItem.h index 998f8eadc..a2a587d13 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem.h +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem.h @@ -22,6 +22,8 @@ #include +#include "SWGMapCoordinate.h" +#include #include #include "SWGObject.h" @@ -66,6 +68,12 @@ public: float getAltitude(); void setAltitude(float altitude); + QList* getTrack(); + void setTrack(QList* track); + + QList* getPredictedTrack(); + void setPredictedTrack(QList* predicted_track); + virtual bool isSet() override; @@ -94,6 +102,12 @@ private: float altitude; bool m_altitude_isSet; + QList* track; + bool m_track_isSet; + + QList* predicted_track; + bool m_predicted_track_isSet; + }; } diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp index 7b4f0c1b8..8d7929069 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.cpp @@ -44,6 +44,10 @@ SWGMapItem_2::SWGMapItem_2() { m_longitude_isSet = false; altitude = 0.0f; m_altitude_isSet = false; + track = nullptr; + m_track_isSet = false; + predicted_track = nullptr; + m_predicted_track_isSet = false; } SWGMapItem_2::~SWGMapItem_2() { @@ -68,6 +72,10 @@ SWGMapItem_2::init() { m_longitude_isSet = false; altitude = 0.0f; m_altitude_isSet = false; + track = new QList(); + m_track_isSet = false; + predicted_track = new QList(); + m_predicted_track_isSet = false; } void @@ -86,6 +94,20 @@ SWGMapItem_2::cleanup() { + if(track != nullptr) { + auto arr = track; + for(auto o: *arr) { + delete o; + } + delete track; + } + if(predicted_track != nullptr) { + auto arr = predicted_track; + for(auto o: *arr) { + delete o; + } + delete predicted_track; + } } SWGMapItem_2* @@ -115,6 +137,10 @@ SWGMapItem_2::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&altitude, pJson["altitude"], "float", ""); + + ::SWGSDRangel::setValue(&track, pJson["track"], "QList", "SWGMapCoordinate"); + + ::SWGSDRangel::setValue(&predicted_track, pJson["predictedTrack"], "QList", "SWGMapCoordinate"); } QString @@ -155,6 +181,12 @@ SWGMapItem_2::asJsonObject() { if(m_altitude_isSet){ obj->insert("altitude", QJsonValue(altitude)); } + if(track && track->size() > 0){ + toJsonArray((QList*)track, obj, "track", "SWGMapCoordinate"); + } + if(predicted_track && predicted_track->size() > 0){ + toJsonArray((QList*)predicted_track, obj, "predictedTrack", "SWGMapCoordinate"); + } return obj; } @@ -239,6 +271,26 @@ SWGMapItem_2::setAltitude(float altitude) { this->m_altitude_isSet = true; } +QList* +SWGMapItem_2::getTrack() { + return track; +} +void +SWGMapItem_2::setTrack(QList* track) { + this->track = track; + this->m_track_isSet = true; +} + +QList* +SWGMapItem_2::getPredictedTrack() { + return predicted_track; +} +void +SWGMapItem_2::setPredictedTrack(QList* predicted_track) { + this->predicted_track = predicted_track; + this->m_predicted_track_isSet = true; +} + bool SWGMapItem_2::isSet(){ @@ -268,6 +320,12 @@ SWGMapItem_2::isSet(){ if(m_altitude_isSet){ isObjectUpdated = true; break; } + if(track && (track->size() > 0)){ + isObjectUpdated = true; break; + } + if(predicted_track && (predicted_track->size() > 0)){ + isObjectUpdated = true; break; + } }while(false); return isObjectUpdated; } diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h index f1b159afd..3ae61bbc6 100644 --- a/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem_2.h @@ -22,6 +22,8 @@ #include +#include "SWGMapCoordinate.h" +#include #include #include "SWGObject.h" @@ -66,6 +68,12 @@ public: float getAltitude(); void setAltitude(float altitude); + QList* getTrack(); + void setTrack(QList* track); + + QList* getPredictedTrack(); + void setPredictedTrack(QList* predicted_track); + virtual bool isSet() override; @@ -94,6 +102,12 @@ private: float altitude; bool m_altitude_isSet; + QList* track; + bool m_track_isSet; + + QList* predicted_track; + bool m_predicted_track_isSet; + }; } diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem_track.cpp b/swagger/sdrangel/code/qt5/client/SWGMapItem_track.cpp new file mode 100644 index 000000000..589a18c57 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem_track.cpp @@ -0,0 +1,154 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGMapItem_track.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGMapItem_track::SWGMapItem_track(QString* json) { + init(); + this->fromJson(*json); +} + +SWGMapItem_track::SWGMapItem_track() { + latitude = 0.0f; + m_latitude_isSet = false; + longitude = 0.0f; + m_longitude_isSet = false; + altitude = 0.0f; + m_altitude_isSet = false; +} + +SWGMapItem_track::~SWGMapItem_track() { + this->cleanup(); +} + +void +SWGMapItem_track::init() { + latitude = 0.0f; + m_latitude_isSet = false; + longitude = 0.0f; + m_longitude_isSet = false; + altitude = 0.0f; + m_altitude_isSet = false; +} + +void +SWGMapItem_track::cleanup() { + + + +} + +SWGMapItem_track* +SWGMapItem_track::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGMapItem_track::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&latitude, pJson["latitude"], "float", ""); + + ::SWGSDRangel::setValue(&longitude, pJson["longitude"], "float", ""); + + ::SWGSDRangel::setValue(&altitude, pJson["altitude"], "float", ""); + +} + +QString +SWGMapItem_track::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGMapItem_track::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_latitude_isSet){ + obj->insert("latitude", QJsonValue(latitude)); + } + if(m_longitude_isSet){ + obj->insert("longitude", QJsonValue(longitude)); + } + if(m_altitude_isSet){ + obj->insert("altitude", QJsonValue(altitude)); + } + + return obj; +} + +float +SWGMapItem_track::getLatitude() { + return latitude; +} +void +SWGMapItem_track::setLatitude(float latitude) { + this->latitude = latitude; + this->m_latitude_isSet = true; +} + +float +SWGMapItem_track::getLongitude() { + return longitude; +} +void +SWGMapItem_track::setLongitude(float longitude) { + this->longitude = longitude; + this->m_longitude_isSet = true; +} + +float +SWGMapItem_track::getAltitude() { + return altitude; +} +void +SWGMapItem_track::setAltitude(float altitude) { + this->altitude = altitude; + this->m_altitude_isSet = true; +} + + +bool +SWGMapItem_track::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_latitude_isSet){ + isObjectUpdated = true; break; + } + if(m_longitude_isSet){ + isObjectUpdated = true; break; + } + if(m_altitude_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGMapItem_track.h b/swagger/sdrangel/code/qt5/client/SWGMapItem_track.h new file mode 100644 index 000000000..ec738bd51 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGMapItem_track.h @@ -0,0 +1,70 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGMapItem_track.h + * + * + */ + +#ifndef SWGMapItem_track_H_ +#define SWGMapItem_track_H_ + +#include + + + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGMapItem_track: public SWGObject { +public: + SWGMapItem_track(); + SWGMapItem_track(QString* json); + virtual ~SWGMapItem_track(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGMapItem_track* fromJson(QString &jsonString) override; + + float getLatitude(); + void setLatitude(float latitude); + + float getLongitude(); + void setLongitude(float longitude); + + float getAltitude(); + void setAltitude(float altitude); + + + virtual bool isSet() override; + +private: + float latitude; + bool m_latitude_isSet; + + float longitude; + bool m_longitude_isSet; + + float altitude; + bool m_altitude_isSet; + +}; + +} + +#endif /* SWGMapItem_track_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h index 301a8ddd5..29792251d 100644 --- a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h +++ b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h @@ -26,6 +26,10 @@ #include "SWGAMModReport.h" #include "SWGAMModSettings.h" #include "SWGAPRSSettings.h" +#include "SWGAPTDemodActions.h" +#include "SWGAPTDemodActions_aos.h" +#include "SWGAPTDemodActions_los.h" +#include "SWGAPTDemodSettings.h" #include "SWGATVDemodSettings.h" #include "SWGATVModReport.h" #include "SWGATVModSettings.h" @@ -146,6 +150,7 @@ #include "SWGLocationInformation.h" #include "SWGLoggingInfo.h" #include "SWGMapActions.h" +#include "SWGMapCoordinate.h" #include "SWGMapItem.h" #include "SWGMapItem_2.h" #include "SWGMapSettings.h" @@ -197,6 +202,7 @@ #include "SWGSSBModSettings.h" #include "SWGSampleRate.h" #include "SWGSamplingDevice.h" +#include "SWGSatelliteTrackerSettings.h" #include "SWGSigMFFileInputActions.h" #include "SWGSigMFFileInputReport.h" #include "SWGSigMFFileInputSettings.h" @@ -285,6 +291,18 @@ namespace SWGSDRangel { if(QString("SWGAPRSSettings").compare(type) == 0) { return new SWGAPRSSettings(); } + if(QString("SWGAPTDemodActions").compare(type) == 0) { + return new SWGAPTDemodActions(); + } + if(QString("SWGAPTDemodActions_aos").compare(type) == 0) { + return new SWGAPTDemodActions_aos(); + } + if(QString("SWGAPTDemodActions_los").compare(type) == 0) { + return new SWGAPTDemodActions_los(); + } + if(QString("SWGAPTDemodSettings").compare(type) == 0) { + return new SWGAPTDemodSettings(); + } if(QString("SWGATVDemodSettings").compare(type) == 0) { return new SWGATVDemodSettings(); } @@ -645,6 +663,9 @@ namespace SWGSDRangel { if(QString("SWGMapActions").compare(type) == 0) { return new SWGMapActions(); } + if(QString("SWGMapCoordinate").compare(type) == 0) { + return new SWGMapCoordinate(); + } if(QString("SWGMapItem").compare(type) == 0) { return new SWGMapItem(); } @@ -798,6 +819,9 @@ namespace SWGSDRangel { if(QString("SWGSamplingDevice").compare(type) == 0) { return new SWGSamplingDevice(); } + if(QString("SWGSatelliteTrackerSettings").compare(type) == 0) { + return new SWGSatelliteTrackerSettings(); + } if(QString("SWGSigMFFileInputActions").compare(type) == 0) { return new SWGSigMFFileInputActions(); } diff --git a/swagger/sdrangel/code/qt5/client/SWGSatelliteTrackerSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGSatelliteTrackerSettings.cpp new file mode 100644 index 000000000..c68983687 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGSatelliteTrackerSettings.cpp @@ -0,0 +1,901 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGSatelliteTrackerSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGSatelliteTrackerSettings::SWGSatelliteTrackerSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGSatelliteTrackerSettings::SWGSatelliteTrackerSettings() { + latitude = 0.0f; + m_latitude_isSet = false; + longitude = 0.0f; + m_longitude_isSet = false; + height_above_sea_level = 0.0f; + m_height_above_sea_level_isSet = false; + target = nullptr; + m_target_isSet = false; + satellites = nullptr; + m_satellites_isSet = false; + tles = nullptr; + m_tles_isSet = false; + date_time = nullptr; + m_date_time_isSet = false; + min_aos_elevation = 0; + m_min_aos_elevation_isSet = false; + min_pass_elevation = 0; + m_min_pass_elevation_isSet = false; + rotator_max_azimuth = 0; + m_rotator_max_azimuth_isSet = false; + rotator_max_elevation = 0; + m_rotator_max_elevation_isSet = false; + az_el_units = 0; + m_az_el_units_isSet = false; + ground_track_points = 0; + m_ground_track_points_isSet = false; + date_format = nullptr; + m_date_format_isSet = false; + utc = 0; + m_utc_isSet = false; + update_period = 0.0f; + m_update_period_isSet = false; + doppler_period = 0.0f; + m_doppler_period_isSet = false; + prediction_period = 0; + m_prediction_period_isSet = false; + pass_start_time = nullptr; + m_pass_start_time_isSet = false; + pass_finish_time = nullptr; + m_pass_finish_time_isSet = false; + default_frequency = 0.0f; + m_default_frequency_isSet = false; + draw_on_map = 0; + m_draw_on_map_isSet = false; + auto_target = 0; + m_auto_target_isSet = false; + aos_speech = nullptr; + m_aos_speech_isSet = false; + los_speech = nullptr; + m_los_speech_isSet = false; + aos_command = nullptr; + m_aos_command_isSet = false; + los_command = nullptr; + m_los_command_isSet = false; + title = nullptr; + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = nullptr; + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +SWGSatelliteTrackerSettings::~SWGSatelliteTrackerSettings() { + this->cleanup(); +} + +void +SWGSatelliteTrackerSettings::init() { + latitude = 0.0f; + m_latitude_isSet = false; + longitude = 0.0f; + m_longitude_isSet = false; + height_above_sea_level = 0.0f; + m_height_above_sea_level_isSet = false; + target = new QString(""); + m_target_isSet = false; + satellites = new QList(); + m_satellites_isSet = false; + tles = new QList(); + m_tles_isSet = false; + date_time = new QString(""); + m_date_time_isSet = false; + min_aos_elevation = 0; + m_min_aos_elevation_isSet = false; + min_pass_elevation = 0; + m_min_pass_elevation_isSet = false; + rotator_max_azimuth = 0; + m_rotator_max_azimuth_isSet = false; + rotator_max_elevation = 0; + m_rotator_max_elevation_isSet = false; + az_el_units = 0; + m_az_el_units_isSet = false; + ground_track_points = 0; + m_ground_track_points_isSet = false; + date_format = new QString(""); + m_date_format_isSet = false; + utc = 0; + m_utc_isSet = false; + update_period = 0.0f; + m_update_period_isSet = false; + doppler_period = 0.0f; + m_doppler_period_isSet = false; + prediction_period = 0; + m_prediction_period_isSet = false; + pass_start_time = new QString(""); + m_pass_start_time_isSet = false; + pass_finish_time = new QString(""); + m_pass_finish_time_isSet = false; + default_frequency = 0.0f; + m_default_frequency_isSet = false; + draw_on_map = 0; + m_draw_on_map_isSet = false; + auto_target = 0; + m_auto_target_isSet = false; + aos_speech = new QString(""); + m_aos_speech_isSet = false; + los_speech = new QString(""); + m_los_speech_isSet = false; + aos_command = new QString(""); + m_aos_command_isSet = false; + los_command = new QString(""); + m_los_command_isSet = false; + title = new QString(""); + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = new QString(""); + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +void +SWGSatelliteTrackerSettings::cleanup() { + + + + if(target != nullptr) { + delete target; + } + if(satellites != nullptr) { + auto arr = satellites; + for(auto o: *arr) { + delete o; + } + delete satellites; + } + if(tles != nullptr) { + auto arr = tles; + for(auto o: *arr) { + delete o; + } + delete tles; + } + if(date_time != nullptr) { + delete date_time; + } + + + + + + + if(date_format != nullptr) { + delete date_format; + } + + + + + if(pass_start_time != nullptr) { + delete pass_start_time; + } + if(pass_finish_time != nullptr) { + delete pass_finish_time; + } + + + + if(aos_speech != nullptr) { + delete aos_speech; + } + if(los_speech != nullptr) { + delete los_speech; + } + if(aos_command != nullptr) { + delete aos_command; + } + if(los_command != nullptr) { + delete los_command; + } + if(title != nullptr) { + delete title; + } + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + +} + +SWGSatelliteTrackerSettings* +SWGSatelliteTrackerSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGSatelliteTrackerSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&latitude, pJson["latitude"], "float", ""); + + ::SWGSDRangel::setValue(&longitude, pJson["longitude"], "float", ""); + + ::SWGSDRangel::setValue(&height_above_sea_level, pJson["heightAboveSeaLevel"], "float", ""); + + ::SWGSDRangel::setValue(&target, pJson["target"], "QString", "QString"); + + + ::SWGSDRangel::setValue(&satellites, pJson["satellites"], "QList", "QString"); + + ::SWGSDRangel::setValue(&tles, pJson["tles"], "QList", "QString"); + ::SWGSDRangel::setValue(&date_time, pJson["dateTime"], "QString", "QString"); + + ::SWGSDRangel::setValue(&min_aos_elevation, pJson["minAOSElevation"], "qint32", ""); + + ::SWGSDRangel::setValue(&min_pass_elevation, pJson["minPassElevation"], "qint32", ""); + + ::SWGSDRangel::setValue(&rotator_max_azimuth, pJson["rotatorMaxAzimuth"], "qint32", ""); + + ::SWGSDRangel::setValue(&rotator_max_elevation, pJson["rotatorMaxElevation"], "qint32", ""); + + ::SWGSDRangel::setValue(&az_el_units, pJson["azElUnits"], "qint32", ""); + + ::SWGSDRangel::setValue(&ground_track_points, pJson["groundTrackPoints"], "qint32", ""); + + ::SWGSDRangel::setValue(&date_format, pJson["dateFormat"], "QString", "QString"); + + ::SWGSDRangel::setValue(&utc, pJson["utc"], "qint32", ""); + + ::SWGSDRangel::setValue(&update_period, pJson["updatePeriod"], "float", ""); + + ::SWGSDRangel::setValue(&doppler_period, pJson["dopplerPeriod"], "float", ""); + + ::SWGSDRangel::setValue(&prediction_period, pJson["predictionPeriod"], "qint32", ""); + + ::SWGSDRangel::setValue(&pass_start_time, pJson["passStartTime"], "QString", "QString"); + + ::SWGSDRangel::setValue(&pass_finish_time, pJson["passFinishTime"], "QString", "QString"); + + ::SWGSDRangel::setValue(&default_frequency, pJson["defaultFrequency"], "float", ""); + + ::SWGSDRangel::setValue(&draw_on_map, pJson["drawOnMap"], "qint32", ""); + + ::SWGSDRangel::setValue(&auto_target, pJson["autoTarget"], "qint32", ""); + + ::SWGSDRangel::setValue(&aos_speech, pJson["aosSpeech"], "QString", "QString"); + + ::SWGSDRangel::setValue(&los_speech, pJson["losSpeech"], "QString", "QString"); + + ::SWGSDRangel::setValue(&aos_command, pJson["aosCommand"], "QString", "QString"); + + ::SWGSDRangel::setValue(&los_command, pJson["losCommand"], "QString", "QString"); + + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", ""); + +} + +QString +SWGSatelliteTrackerSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGSatelliteTrackerSettings::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_latitude_isSet){ + obj->insert("latitude", QJsonValue(latitude)); + } + if(m_longitude_isSet){ + obj->insert("longitude", QJsonValue(longitude)); + } + if(m_height_above_sea_level_isSet){ + obj->insert("heightAboveSeaLevel", QJsonValue(height_above_sea_level)); + } + if(target != nullptr && *target != QString("")){ + toJsonValue(QString("target"), target, obj, QString("QString")); + } + if(satellites && satellites->size() > 0){ + toJsonArray((QList*)satellites, obj, "satellites", "QString"); + } + if(tles && tles->size() > 0){ + toJsonArray((QList*)tles, obj, "tles", "QString"); + } + if(date_time != nullptr && *date_time != QString("")){ + toJsonValue(QString("dateTime"), date_time, obj, QString("QString")); + } + if(m_min_aos_elevation_isSet){ + obj->insert("minAOSElevation", QJsonValue(min_aos_elevation)); + } + if(m_min_pass_elevation_isSet){ + obj->insert("minPassElevation", QJsonValue(min_pass_elevation)); + } + if(m_rotator_max_azimuth_isSet){ + obj->insert("rotatorMaxAzimuth", QJsonValue(rotator_max_azimuth)); + } + if(m_rotator_max_elevation_isSet){ + obj->insert("rotatorMaxElevation", QJsonValue(rotator_max_elevation)); + } + if(m_az_el_units_isSet){ + obj->insert("azElUnits", QJsonValue(az_el_units)); + } + if(m_ground_track_points_isSet){ + obj->insert("groundTrackPoints", QJsonValue(ground_track_points)); + } + if(date_format != nullptr && *date_format != QString("")){ + toJsonValue(QString("dateFormat"), date_format, obj, QString("QString")); + } + if(m_utc_isSet){ + obj->insert("utc", QJsonValue(utc)); + } + if(m_update_period_isSet){ + obj->insert("updatePeriod", QJsonValue(update_period)); + } + if(m_doppler_period_isSet){ + obj->insert("dopplerPeriod", QJsonValue(doppler_period)); + } + if(m_prediction_period_isSet){ + obj->insert("predictionPeriod", QJsonValue(prediction_period)); + } + if(pass_start_time != nullptr && *pass_start_time != QString("")){ + toJsonValue(QString("passStartTime"), pass_start_time, obj, QString("QString")); + } + if(pass_finish_time != nullptr && *pass_finish_time != QString("")){ + toJsonValue(QString("passFinishTime"), pass_finish_time, obj, QString("QString")); + } + if(m_default_frequency_isSet){ + obj->insert("defaultFrequency", QJsonValue(default_frequency)); + } + if(m_draw_on_map_isSet){ + obj->insert("drawOnMap", QJsonValue(draw_on_map)); + } + if(m_auto_target_isSet){ + obj->insert("autoTarget", QJsonValue(auto_target)); + } + if(aos_speech != nullptr && *aos_speech != QString("")){ + toJsonValue(QString("aosSpeech"), aos_speech, obj, QString("QString")); + } + if(los_speech != nullptr && *los_speech != QString("")){ + toJsonValue(QString("losSpeech"), los_speech, obj, QString("QString")); + } + if(aos_command != nullptr && *aos_command != QString("")){ + toJsonValue(QString("aosCommand"), aos_command, obj, QString("QString")); + } + if(los_command != nullptr && *los_command != QString("")){ + toJsonValue(QString("losCommand"), los_command, obj, QString("QString")); + } + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + if(m_use_reverse_api_isSet){ + obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); + } + if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ + toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString")); + } + if(m_reverse_api_port_isSet){ + obj->insert("reverseAPIPort", QJsonValue(reverse_api_port)); + } + if(m_reverse_api_device_index_isSet){ + obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index)); + } + if(m_reverse_api_channel_index_isSet){ + obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index)); + } + + return obj; +} + +float +SWGSatelliteTrackerSettings::getLatitude() { + return latitude; +} +void +SWGSatelliteTrackerSettings::setLatitude(float latitude) { + this->latitude = latitude; + this->m_latitude_isSet = true; +} + +float +SWGSatelliteTrackerSettings::getLongitude() { + return longitude; +} +void +SWGSatelliteTrackerSettings::setLongitude(float longitude) { + this->longitude = longitude; + this->m_longitude_isSet = true; +} + +float +SWGSatelliteTrackerSettings::getHeightAboveSeaLevel() { + return height_above_sea_level; +} +void +SWGSatelliteTrackerSettings::setHeightAboveSeaLevel(float height_above_sea_level) { + this->height_above_sea_level = height_above_sea_level; + this->m_height_above_sea_level_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getTarget() { + return target; +} +void +SWGSatelliteTrackerSettings::setTarget(QString* target) { + this->target = target; + this->m_target_isSet = true; +} + +QList* +SWGSatelliteTrackerSettings::getSatellites() { + return satellites; +} +void +SWGSatelliteTrackerSettings::setSatellites(QList* satellites) { + this->satellites = satellites; + this->m_satellites_isSet = true; +} + +QList* +SWGSatelliteTrackerSettings::getTles() { + return tles; +} +void +SWGSatelliteTrackerSettings::setTles(QList* tles) { + this->tles = tles; + this->m_tles_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getDateTime() { + return date_time; +} +void +SWGSatelliteTrackerSettings::setDateTime(QString* date_time) { + this->date_time = date_time; + this->m_date_time_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getMinAosElevation() { + return min_aos_elevation; +} +void +SWGSatelliteTrackerSettings::setMinAosElevation(qint32 min_aos_elevation) { + this->min_aos_elevation = min_aos_elevation; + this->m_min_aos_elevation_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getMinPassElevation() { + return min_pass_elevation; +} +void +SWGSatelliteTrackerSettings::setMinPassElevation(qint32 min_pass_elevation) { + this->min_pass_elevation = min_pass_elevation; + this->m_min_pass_elevation_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getRotatorMaxAzimuth() { + return rotator_max_azimuth; +} +void +SWGSatelliteTrackerSettings::setRotatorMaxAzimuth(qint32 rotator_max_azimuth) { + this->rotator_max_azimuth = rotator_max_azimuth; + this->m_rotator_max_azimuth_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getRotatorMaxElevation() { + return rotator_max_elevation; +} +void +SWGSatelliteTrackerSettings::setRotatorMaxElevation(qint32 rotator_max_elevation) { + this->rotator_max_elevation = rotator_max_elevation; + this->m_rotator_max_elevation_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getAzElUnits() { + return az_el_units; +} +void +SWGSatelliteTrackerSettings::setAzElUnits(qint32 az_el_units) { + this->az_el_units = az_el_units; + this->m_az_el_units_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getGroundTrackPoints() { + return ground_track_points; +} +void +SWGSatelliteTrackerSettings::setGroundTrackPoints(qint32 ground_track_points) { + this->ground_track_points = ground_track_points; + this->m_ground_track_points_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getDateFormat() { + return date_format; +} +void +SWGSatelliteTrackerSettings::setDateFormat(QString* date_format) { + this->date_format = date_format; + this->m_date_format_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getUtc() { + return utc; +} +void +SWGSatelliteTrackerSettings::setUtc(qint32 utc) { + this->utc = utc; + this->m_utc_isSet = true; +} + +float +SWGSatelliteTrackerSettings::getUpdatePeriod() { + return update_period; +} +void +SWGSatelliteTrackerSettings::setUpdatePeriod(float update_period) { + this->update_period = update_period; + this->m_update_period_isSet = true; +} + +float +SWGSatelliteTrackerSettings::getDopplerPeriod() { + return doppler_period; +} +void +SWGSatelliteTrackerSettings::setDopplerPeriod(float doppler_period) { + this->doppler_period = doppler_period; + this->m_doppler_period_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getPredictionPeriod() { + return prediction_period; +} +void +SWGSatelliteTrackerSettings::setPredictionPeriod(qint32 prediction_period) { + this->prediction_period = prediction_period; + this->m_prediction_period_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getPassStartTime() { + return pass_start_time; +} +void +SWGSatelliteTrackerSettings::setPassStartTime(QString* pass_start_time) { + this->pass_start_time = pass_start_time; + this->m_pass_start_time_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getPassFinishTime() { + return pass_finish_time; +} +void +SWGSatelliteTrackerSettings::setPassFinishTime(QString* pass_finish_time) { + this->pass_finish_time = pass_finish_time; + this->m_pass_finish_time_isSet = true; +} + +float +SWGSatelliteTrackerSettings::getDefaultFrequency() { + return default_frequency; +} +void +SWGSatelliteTrackerSettings::setDefaultFrequency(float default_frequency) { + this->default_frequency = default_frequency; + this->m_default_frequency_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getDrawOnMap() { + return draw_on_map; +} +void +SWGSatelliteTrackerSettings::setDrawOnMap(qint32 draw_on_map) { + this->draw_on_map = draw_on_map; + this->m_draw_on_map_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getAutoTarget() { + return auto_target; +} +void +SWGSatelliteTrackerSettings::setAutoTarget(qint32 auto_target) { + this->auto_target = auto_target; + this->m_auto_target_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getAosSpeech() { + return aos_speech; +} +void +SWGSatelliteTrackerSettings::setAosSpeech(QString* aos_speech) { + this->aos_speech = aos_speech; + this->m_aos_speech_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getLosSpeech() { + return los_speech; +} +void +SWGSatelliteTrackerSettings::setLosSpeech(QString* los_speech) { + this->los_speech = los_speech; + this->m_los_speech_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getAosCommand() { + return aos_command; +} +void +SWGSatelliteTrackerSettings::setAosCommand(QString* aos_command) { + this->aos_command = aos_command; + this->m_aos_command_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getLosCommand() { + return los_command; +} +void +SWGSatelliteTrackerSettings::setLosCommand(QString* los_command) { + this->los_command = los_command; + this->m_los_command_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getTitle() { + return title; +} +void +SWGSatelliteTrackerSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getRgbColor() { + return rgb_color; +} +void +SWGSatelliteTrackerSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGSatelliteTrackerSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGSatelliteTrackerSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGSatelliteTrackerSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGSatelliteTrackerSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGSatelliteTrackerSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGSatelliteTrackerSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGSatelliteTrackerSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + + +bool +SWGSatelliteTrackerSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_latitude_isSet){ + isObjectUpdated = true; break; + } + if(m_longitude_isSet){ + isObjectUpdated = true; break; + } + if(m_height_above_sea_level_isSet){ + isObjectUpdated = true; break; + } + if(target && *target != QString("")){ + isObjectUpdated = true; break; + } + if(satellites && (satellites->size() > 0)){ + isObjectUpdated = true; break; + } + if(tles && (tles->size() > 0)){ + isObjectUpdated = true; break; + } + if(date_time && *date_time != QString("")){ + isObjectUpdated = true; break; + } + if(m_min_aos_elevation_isSet){ + isObjectUpdated = true; break; + } + if(m_min_pass_elevation_isSet){ + isObjectUpdated = true; break; + } + if(m_rotator_max_azimuth_isSet){ + isObjectUpdated = true; break; + } + if(m_rotator_max_elevation_isSet){ + isObjectUpdated = true; break; + } + if(m_az_el_units_isSet){ + isObjectUpdated = true; break; + } + if(m_ground_track_points_isSet){ + isObjectUpdated = true; break; + } + if(date_format && *date_format != QString("")){ + isObjectUpdated = true; break; + } + if(m_utc_isSet){ + isObjectUpdated = true; break; + } + if(m_update_period_isSet){ + isObjectUpdated = true; break; + } + if(m_doppler_period_isSet){ + isObjectUpdated = true; break; + } + if(m_prediction_period_isSet){ + isObjectUpdated = true; break; + } + if(pass_start_time && *pass_start_time != QString("")){ + isObjectUpdated = true; break; + } + if(pass_finish_time && *pass_finish_time != QString("")){ + isObjectUpdated = true; break; + } + if(m_default_frequency_isSet){ + isObjectUpdated = true; break; + } + if(m_draw_on_map_isSet){ + isObjectUpdated = true; break; + } + if(m_auto_target_isSet){ + isObjectUpdated = true; break; + } + if(aos_speech && *aos_speech != QString("")){ + isObjectUpdated = true; break; + } + if(los_speech && *los_speech != QString("")){ + isObjectUpdated = true; break; + } + if(aos_command && *aos_command != QString("")){ + isObjectUpdated = true; break; + } + if(los_command && *los_command != QString("")){ + isObjectUpdated = true; break; + } + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + isObjectUpdated = true; break; + } + if(m_use_reverse_api_isSet){ + isObjectUpdated = true; break; + } + if(reverse_api_address && *reverse_api_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_reverse_api_port_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_device_index_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_channel_index_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGSatelliteTrackerSettings.h b/swagger/sdrangel/code/qt5/client/SWGSatelliteTrackerSettings.h new file mode 100644 index 000000000..57f8aaac6 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGSatelliteTrackerSettings.h @@ -0,0 +1,258 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGSatelliteTrackerSettings.h + * + * Satellite Tracker settings + */ + +#ifndef SWGSatelliteTrackerSettings_H_ +#define SWGSatelliteTrackerSettings_H_ + +#include + + +#include +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGSatelliteTrackerSettings: public SWGObject { +public: + SWGSatelliteTrackerSettings(); + SWGSatelliteTrackerSettings(QString* json); + virtual ~SWGSatelliteTrackerSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGSatelliteTrackerSettings* fromJson(QString &jsonString) override; + + float getLatitude(); + void setLatitude(float latitude); + + float getLongitude(); + void setLongitude(float longitude); + + float getHeightAboveSeaLevel(); + void setHeightAboveSeaLevel(float height_above_sea_level); + + QString* getTarget(); + void setTarget(QString* target); + + QList* getSatellites(); + void setSatellites(QList* satellites); + + QList* getTles(); + void setTles(QList* tles); + + QString* getDateTime(); + void setDateTime(QString* date_time); + + qint32 getMinAosElevation(); + void setMinAosElevation(qint32 min_aos_elevation); + + qint32 getMinPassElevation(); + void setMinPassElevation(qint32 min_pass_elevation); + + qint32 getRotatorMaxAzimuth(); + void setRotatorMaxAzimuth(qint32 rotator_max_azimuth); + + qint32 getRotatorMaxElevation(); + void setRotatorMaxElevation(qint32 rotator_max_elevation); + + qint32 getAzElUnits(); + void setAzElUnits(qint32 az_el_units); + + qint32 getGroundTrackPoints(); + void setGroundTrackPoints(qint32 ground_track_points); + + QString* getDateFormat(); + void setDateFormat(QString* date_format); + + qint32 getUtc(); + void setUtc(qint32 utc); + + float getUpdatePeriod(); + void setUpdatePeriod(float update_period); + + float getDopplerPeriod(); + void setDopplerPeriod(float doppler_period); + + qint32 getPredictionPeriod(); + void setPredictionPeriod(qint32 prediction_period); + + QString* getPassStartTime(); + void setPassStartTime(QString* pass_start_time); + + QString* getPassFinishTime(); + void setPassFinishTime(QString* pass_finish_time); + + float getDefaultFrequency(); + void setDefaultFrequency(float default_frequency); + + qint32 getDrawOnMap(); + void setDrawOnMap(qint32 draw_on_map); + + qint32 getAutoTarget(); + void setAutoTarget(qint32 auto_target); + + QString* getAosSpeech(); + void setAosSpeech(QString* aos_speech); + + QString* getLosSpeech(); + void setLosSpeech(QString* los_speech); + + QString* getAosCommand(); + void setAosCommand(QString* aos_command); + + QString* getLosCommand(); + void setLosCommand(QString* los_command); + + QString* getTitle(); + void setTitle(QString* title); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + qint32 getUseReverseApi(); + void setUseReverseApi(qint32 use_reverse_api); + + QString* getReverseApiAddress(); + void setReverseApiAddress(QString* reverse_api_address); + + qint32 getReverseApiPort(); + void setReverseApiPort(qint32 reverse_api_port); + + qint32 getReverseApiDeviceIndex(); + void setReverseApiDeviceIndex(qint32 reverse_api_device_index); + + qint32 getReverseApiChannelIndex(); + void setReverseApiChannelIndex(qint32 reverse_api_channel_index); + + + virtual bool isSet() override; + +private: + float latitude; + bool m_latitude_isSet; + + float longitude; + bool m_longitude_isSet; + + float height_above_sea_level; + bool m_height_above_sea_level_isSet; + + QString* target; + bool m_target_isSet; + + QList* satellites; + bool m_satellites_isSet; + + QList* tles; + bool m_tles_isSet; + + QString* date_time; + bool m_date_time_isSet; + + qint32 min_aos_elevation; + bool m_min_aos_elevation_isSet; + + qint32 min_pass_elevation; + bool m_min_pass_elevation_isSet; + + qint32 rotator_max_azimuth; + bool m_rotator_max_azimuth_isSet; + + qint32 rotator_max_elevation; + bool m_rotator_max_elevation_isSet; + + qint32 az_el_units; + bool m_az_el_units_isSet; + + qint32 ground_track_points; + bool m_ground_track_points_isSet; + + QString* date_format; + bool m_date_format_isSet; + + qint32 utc; + bool m_utc_isSet; + + float update_period; + bool m_update_period_isSet; + + float doppler_period; + bool m_doppler_period_isSet; + + qint32 prediction_period; + bool m_prediction_period_isSet; + + QString* pass_start_time; + bool m_pass_start_time_isSet; + + QString* pass_finish_time; + bool m_pass_finish_time_isSet; + + float default_frequency; + bool m_default_frequency_isSet; + + qint32 draw_on_map; + bool m_draw_on_map_isSet; + + qint32 auto_target; + bool m_auto_target_isSet; + + QString* aos_speech; + bool m_aos_speech_isSet; + + QString* los_speech; + bool m_los_speech_isSet; + + QString* aos_command; + bool m_aos_command_isSet; + + QString* los_command; + bool m_los_command_isSet; + + QString* title; + bool m_title_isSet; + + qint32 rgb_color; + bool m_rgb_color_isSet; + + qint32 use_reverse_api; + bool m_use_reverse_api_isSet; + + QString* reverse_api_address; + bool m_reverse_api_address_isSet; + + qint32 reverse_api_port; + bool m_reverse_api_port_isSet; + + qint32 reverse_api_device_index; + bool m_reverse_api_device_index_isSet; + + qint32 reverse_api_channel_index; + bool m_reverse_api_channel_index_isSet; + +}; + +} + +#endif /* SWGSatelliteTrackerSettings_H_ */