From 97f55be6e92178d84781cd392997337c18bea63a Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Fri, 4 Feb 2022 16:57:45 +0000 Subject: [PATCH] ADS-B Demod Updates Add support for animated 3D models. Downloaded zipped airplane database as 1/4 of the size. Add table context menu. Add airline and country images to text bubbles on maps. Fix calculation of ground speed when on surface. Fix position calculation when aircraft transistions from surface to air. Fix altitude calculation when Q-bit is set. Speed up processing of large log files. Add new airline logos. --- plugins/channelrx/demodadsb/CMakeLists.txt | 6 + .../demodadsb/adsbdemoddisplaydialog.cpp | 74 +- .../demodadsb/adsbdemoddisplaydialog.h | 24 +- .../demodadsb/adsbdemoddisplaydialog.ui | 381 ++-- plugins/channelrx/demodadsb/adsbdemodgui.cpp | 1665 ++++++++++++++--- plugins/channelrx/demodadsb/adsbdemodgui.h | 139 +- plugins/channelrx/demodadsb/adsbdemodgui.ui | 20 +- plugins/channelrx/demodadsb/adsbdemodreport.h | 12 +- .../channelrx/demodadsb/adsbdemodsettings.cpp | 8 + .../channelrx/demodadsb/adsbdemodsettings.h | 2 + plugins/channelrx/demodadsb/adsbdemodsink.cpp | 8 + plugins/channelrx/demodadsb/adsbdemodsink.h | 2 + .../demodadsb/adsbdemodsinkworker.cpp | 19 +- .../channelrx/demodadsb/adsbdemodsinkworker.h | 3 + plugins/channelrx/demodadsb/airlinelogos.qrc | 24 + .../channelrx/demodadsb/airlinelogos/AIO.bmp | Bin 0 -> 6938 bytes .../channelrx/demodadsb/airlinelogos/BCS.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/BEA.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/BEE.bmp | Bin 2840 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/BEL.bmp | Bin 5176 -> 5176 bytes .../demodadsb/airlinelogos/BELold.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/BHL.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/CAT.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/CATa.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/DHA.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/DHK.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/DHL.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/DHV.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/DHX.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/FJO.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/FPYb.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/GGT.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/GPX.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/HGB.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/ITY.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/JES.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/JOS.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/KRU.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/MAY.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/NAC.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/NDA.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/NVR.bmp | Bin 5176 -> 6856 bytes .../demodadsb/airlinelogos/NVROLD.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/OCN.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/PXT.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/RBS.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/RUK.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/RYR.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/RYS.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/SHF.bmp | Bin 0 -> 5174 bytes .../demodadsb/airlinelogos/SKYPARK.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/TES.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/TMT.bmp | Bin 0 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/VEC.bmp | Bin 5176 -> 5176 bytes .../channelrx/demodadsb/airlinelogos/WDY.bmp | Bin 0 -> 5176 bytes plugins/channelrx/demodadsb/map/map.qml | 27 +- plugins/channelrx/demodadsb/osndb.h | 2 +- plugins/channelrx/demodadsb/readme.md | 5 + 58 files changed, 1928 insertions(+), 493 deletions(-) create mode 100644 plugins/channelrx/demodadsb/airlinelogos/AIO.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/BCS.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/BEA.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/BELold.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/CATa.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/DHA.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/FJO.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/FPYb.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/GGT.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/GPX.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/HGB.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/ITY.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/JOS.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/KRU.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/NDA.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/NVROLD.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/OCN.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/PXT.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/RBS.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/RYS.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/SHF.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/SKYPARK.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/TES.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/TMT.bmp create mode 100644 plugins/channelrx/demodadsb/airlinelogos/WDY.bmp diff --git a/plugins/channelrx/demodadsb/CMakeLists.txt b/plugins/channelrx/demodadsb/CMakeLists.txt index 4691c1ca3..a09617f5e 100644 --- a/plugins/channelrx/demodadsb/CMakeLists.txt +++ b/plugins/channelrx/demodadsb/CMakeLists.txt @@ -29,6 +29,7 @@ set(adsb_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${Boost_INCLUDE_DIRS} + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} ) if(NOT SERVER_MODE) @@ -94,3 +95,8 @@ if(WIN32) include(DeployQt) windeployqt(${TARGET_NAME} ${SDRANGEL_BINARY_BIN_DIR} ${PROJECT_SOURCE_DIR}/map) endif() + +# Install debug symbols +if (WIN32) + install(FILES $ CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} ) +endif() diff --git a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp index 5a27fb46f..bec7c32de 100644 --- a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp +++ b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.cpp @@ -20,36 +20,35 @@ #include "adsbdemoddisplaydialog.h" -ADSBDemodDisplayDialog::ADSBDemodDisplayDialog( - int removeTimeout, float airportRange, ADSBDemodSettings::AirportType airportMinimumSize, - bool displayHeliports, bool siUnits, QString fontName, int fontSize, bool displayDemodStats, - bool autoResizeTableColumns, const QString& apiKey, QStringList airspaces, float airspaceRange, - ADSBDemodSettings::MapType mapType, bool displayNavAids, bool displayPhotos, QWidget* parent) : +ADSBDemodDisplayDialog::ADSBDemodDisplayDialog(ADSBDemodSettings *settings, QWidget* parent) : QDialog(parent), - m_fontName(fontName), - m_fontSize(fontSize), - ui(new Ui::ADSBDemodDisplayDialog) + ui(new Ui::ADSBDemodDisplayDialog), + m_settings(settings), + m_fontName(settings->m_tableFontName), + m_fontSize(settings->m_tableFontSize) { ui->setupUi(this); - ui->timeout->setValue(removeTimeout); - ui->airportRange->setValue(airportRange); - ui->airportSize->setCurrentIndex((int)airportMinimumSize); - ui->heliports->setChecked(displayHeliports); - ui->units->setCurrentIndex((int)siUnits); - ui->displayStats->setChecked(displayDemodStats); - ui->autoResizeTableColumns->setChecked(autoResizeTableColumns); - ui->apiKey->setText(apiKey); - for (const auto& airspace: airspaces) + ui->timeout->setValue(settings->m_removeTimeout); + ui->airportRange->setValue(settings->m_airportRange); + ui->airportSize->setCurrentIndex((int)settings->m_airportMinimumSize); + ui->heliports->setChecked(settings->m_displayHeliports); + ui->units->setCurrentIndex((int)settings->m_siUnits); + ui->displayStats->setChecked(settings->m_displayDemodStats); + ui->autoResizeTableColumns->setChecked(settings->m_autoResizeTableColumns); + ui->apiKey->setText(settings->m_apiKey); + for (const auto& airspace: settings->m_airspaces) { QList items = ui->airspaces->findItems(airspace, Qt::MatchExactly); for (const auto& item: items) { item->setCheckState(Qt::Checked); } } - ui->airspaceRange->setValue(airspaceRange); - ui->mapType->setCurrentIndex((int)mapType); - ui->navAids->setChecked(displayNavAids); - ui->photos->setChecked(displayPhotos); + ui->airspaceRange->setValue(settings->m_airspaceRange); + ui->mapType->setCurrentIndex((int)settings->m_mapType); + ui->navAids->setChecked(settings->m_displayNavAids); + ui->photos->setChecked(settings->m_displayPhotos); + ui->verboseModelMatching->setChecked(settings->m_verboseModelMatching); + ui->airfieldElevation->setValue(settings->m_airfieldElevation); } ADSBDemodDisplayDialog::~ADSBDemodDisplayDialog() @@ -59,26 +58,30 @@ ADSBDemodDisplayDialog::~ADSBDemodDisplayDialog() void ADSBDemodDisplayDialog::accept() { - m_removeTimeout = ui->timeout->value(); - m_airportRange = ui->airportRange->value(); - m_airportMinimumSize = (ADSBDemodSettings::AirportType)ui->airportSize->currentIndex(); - m_displayHeliports = ui->heliports->isChecked(); - m_siUnits = ui->units->currentIndex() == 0 ? false : true; - m_displayDemodStats = ui->displayStats->isChecked(); - m_autoResizeTableColumns = ui->autoResizeTableColumns->isChecked(); - m_apiKey = ui->apiKey->text(); - m_airspaces = QStringList(); + m_settings->m_removeTimeout = ui->timeout->value(); + m_settings->m_airportRange = ui->airportRange->value(); + m_settings->m_airportMinimumSize = (ADSBDemodSettings::AirportType)ui->airportSize->currentIndex(); + m_settings->m_displayHeliports = ui->heliports->isChecked(); + m_settings->m_siUnits = ui->units->currentIndex() == 0 ? false : true; + m_settings->m_displayDemodStats = ui->displayStats->isChecked(); + m_settings->m_autoResizeTableColumns = ui->autoResizeTableColumns->isChecked(); + m_settings->m_apiKey = ui->apiKey->text(); + m_settings->m_airspaces = QStringList(); for (int i = 0; i < ui->airspaces->count(); i++) { QListWidgetItem *item = ui->airspaces->item(i); if (item->checkState() == Qt::Checked) { - m_airspaces.append(item->text()); + m_settings->m_airspaces.append(item->text()); } } - m_airspaceRange = ui->airspaceRange->value(); - m_mapType = (ADSBDemodSettings::MapType)ui->mapType->currentIndex(); - m_displayNavAids = ui->navAids->isChecked(); - m_displayPhotos = ui->photos->isChecked(); + m_settings->m_airspaceRange = ui->airspaceRange->value(); + m_settings->m_mapType = (ADSBDemodSettings::MapType)ui->mapType->currentIndex(); + m_settings->m_displayNavAids = ui->navAids->isChecked(); + m_settings->m_displayPhotos = ui->photos->isChecked(); + m_settings->m_verboseModelMatching = ui->verboseModelMatching->isChecked(); + m_settings->m_airfieldElevation = ui->airfieldElevation->value(); + m_settings->m_tableFontName = m_fontName; + m_settings->m_tableFontSize = m_fontSize; QDialog::accept(); } @@ -88,7 +91,6 @@ void ADSBDemodDisplayDialog::on_font_clicked() QFont font = QFontDialog::getFont(&ok, QFont(m_fontName, m_fontSize), this); if (ok) { - qDebug() << font; m_fontName = font.family(); m_fontSize = font.pointSize(); } diff --git a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.h b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.h index 66b9a04f6..d83b6bc70 100644 --- a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.h +++ b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.h @@ -25,34 +25,18 @@ class ADSBDemodDisplayDialog : public QDialog { Q_OBJECT public: - explicit ADSBDemodDisplayDialog(int removeTimeout, float airportRange, ADSBDemodSettings::AirportType airportMinimumSize, - bool displayHeliports, bool siUnits, QString fontName, int fontSize, bool displayDemodStats, - bool autoResizeTableColumns, const QString& apiKey, QStringList airspaces, float airspaceRange, - ADSBDemodSettings::MapType mapType, bool displayNavAids, bool displayPhotos, QWidget* parent = 0); + explicit ADSBDemodDisplayDialog(ADSBDemodSettings *settings, QWidget* parent = 0); ~ADSBDemodDisplayDialog(); - int m_removeTimeout; - float m_airportRange; - ADSBDemodSettings::AirportType m_airportMinimumSize; - bool m_displayHeliports; - bool m_siUnits; - QString m_fontName; - int m_fontSize; - bool m_displayDemodStats; - bool m_autoResizeTableColumns; - QString m_apiKey; - QStringList m_airspaces; - float m_airspaceRange; - ADSBDemodSettings::MapType m_mapType; - bool m_displayNavAids; - bool m_displayPhotos; - private slots: void accept(); void on_font_clicked(); private: Ui::ADSBDemodDisplayDialog* ui; + ADSBDemodSettings *m_settings; + QString m_fontName; + int m_fontSize; }; #endif // INCLUDE_ADSBDEMODDISPLAYDIALOG_H diff --git a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui index 5ae7f0222..6e6426168 100644 --- a/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui +++ b/plugins/channelrx/demodadsb/adsbdemoddisplaydialog.ui @@ -7,12 +7,11 @@ 0 0 417 - 638 + 692 - Liberation Sans 9 @@ -23,20 +22,57 @@ - - - + + + + + 0 + 0 + + + Display demodulator statistics + + + - - - - Displays airports within the specified distance in kilometres from My Position + + + + Display NAVAIDs - - 20000 + + + + + + The units to use for altitude, speed and climb rate + + + + ft, kn, ft/min + + + + + m, kph, m/s + + + + + + + + Airspaces to display + + + + + + + avaitionstack API key @@ -50,6 +86,47 @@ + + + + Display heliports + + + + + + + Displays airspace within the specified distance in kilometres from My Position + + + 20000 + + + + + + + Log 3D model matching information + + + + + + + Resize columns after adding aircraft + + + + + + + Display NAVAIDs such as VORs and NDBs + + + + + + @@ -57,20 +134,109 @@ - - + + - Airspaces to display + Airport display distance (km) - + + + + Displays airports within the specified distance in kilometres from My Position + + + 20000 + + + + + + + Display demodulator statistics + + + + + + + Display airports with size + + + + aviationstack.com API key for accessing flight information + + + + Display aircraft photos + + + + + + + Log information about how aircraft are matched to 3D models + + + + + + + + + + Aircraft timeout (s) + + + + + + + Units + + + + + + + Table font + + + + + + + Type of map to display + + + + Aviation + + + + + Aviation (Dark) + + + + + Street + + + + + Satellite + + + + @@ -228,27 +394,13 @@ - - + + - Resize the columns in the table after an aircraft is added to it + Select a font for the table - - - - - - - - Display NAVAIDs - - - - - - - Resize columns after adding aircraft + Select... @@ -274,128 +426,16 @@ - - - - Display heliports - - - - - - - - 0 - 0 - - + + - Display demodulator statistics + Download and display photos of highlighted aircraft - - - - Display airports with size - - - - - - - avaitionstack API key - - - - - - - Aircraft timeout (s) - - - - - - - Displays airspace within the specified distance in kilometres from My Position - - - 20000 - - - - - - - The units to use for altitude, speed and climb rate - - - - ft, kn, ft/min - - - - - m, kph, m/s - - - - - - - - Units - - - - - - - Select a font for the table - - - Select... - - - - - - - Airport display distance (km) - - - - - - - Type of map to display - - - - Aviation - - - - - Aviation (Dark) - - - - - Street - - - - - Satellite - - - - @@ -403,6 +443,16 @@ + + + + Resize the columns in the table after an aircraft is added to it + + + + + + @@ -413,37 +463,26 @@ - - + + - Table font + Airfield barometric altitude (ft) - - + + - Display NAVAIDs such as VORs and NDBs + Barometric altitude reported by aircraft when on airfield surface - - + + -10000 - - - - - - Display aircraft photos + + 30000 - - - - - - Download and display photos of highlighted aircraft - - - + + 10 diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index 228f7e0e7..e0a303b80 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -29,13 +29,15 @@ #include #include #include +#include #include #include -#include "SWGMapItem.h" +#include #include "ui_adsbdemodgui.h" #include "channel/channelwebapiutils.h" +#include "feature/featurewebapiutils.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" @@ -87,12 +89,15 @@ QByteArray ADSBDemodGUI::serialize() const bool ADSBDemodGUI::deserialize(const QByteArray& data) { - if(m_settings.deserialize(data)) { + if(m_settings.deserialize(data)) + { updateDeviceSetList(); displaySettings(); applySettings(true); return true; - } else { + } + else + { resetToDefaults(); return false; } @@ -102,11 +107,17 @@ bool ADSBDemodGUI::deserialize(const QByteArray& data) static int cprNL(double lat) { if (lat == 0.0) + { return 59; + } else if ((lat == 87.0) || (lat == -87.0)) + { return 2; + } else if ((lat > 87.0) || (lat < -87.0)) + { return 1; + } else { double nz = 15.0; @@ -119,10 +130,11 @@ static int cprNL(double lat) static int cprN(double lat, int odd) { int nl = cprNL(lat) - odd; - if (nl > 1) + if (nl > 1) { return nl; - else + } else { return 1; + } } // Can't use std::fmod, as that works differently for negative numbers (See C.2.6.2) @@ -131,71 +143,94 @@ static Real modulus(double x, double y) return x - y * std::floor(x/y); } -QString Aircraft::getImage() +QString Aircraft::getImage() const { if (m_emitterCategory.length() > 0) { - if (!m_emitterCategory.compare("Heavy")) - return QString("aircraft_4engine.png"); - else if (!m_emitterCategory.compare("Large")) + if (!m_emitterCategory.compare("Heavy")) { + return QString("aircraft_4engine.png"); // Can also be 777, 787 + } else if (!m_emitterCategory.compare("Large")) { return QString("aircraft_2engine.png"); - else if (!m_emitterCategory.compare("Small")) + } else if (!m_emitterCategory.compare("Small")) { return QString("aircraft_2enginesmall.png"); - else if (!m_emitterCategory.compare("Rotorcraft")) + } else if (!m_emitterCategory.compare("Rotorcraft")) { return QString("aircraft_helicopter.png"); - else if (!m_emitterCategory.compare("High performance")) + } else if (!m_emitterCategory.compare("High performance")) { return QString("aircraft_fighter.png"); - else if (!m_emitterCategory.compare("Light") + } else if (!m_emitterCategory.compare("Light") || !m_emitterCategory.compare("Ultralight") - || !m_emitterCategory.compare("Glider/sailplane")) + || !m_emitterCategory.compare("Glider/sailplane")) { return QString("aircraft_light.png"); - else if (!m_emitterCategory.compare("Space vehicle")) + } else if (!m_emitterCategory.compare("Space vehicle")) { return QString("aircraft_space.png"); - else if (!m_emitterCategory.compare("UAV")) + } else if (!m_emitterCategory.compare("UAV")) { return QString("aircraft_drone.png"); - else if (!m_emitterCategory.compare("Emergency vehicle") - || !m_emitterCategory.compare("Service vehicle")) + } else if (!m_emitterCategory.compare("Emergency vehicle") + || !m_emitterCategory.compare("Service vehicle")) { return QString("truck.png"); - else + } else { return QString("aircraft_2engine.png"); + } } else + { return QString("aircraft_2engine.png"); + } } -QString Aircraft::getText(bool all) +QString Aircraft::getText(bool all) const { QStringList list; - if (m_callsign.length() > 0) - { - list.append(QString("Callsign: %1").arg(m_callsign)); - } - else - { - list.append(QString("ICAO: %1").arg(m_icao, 1, 16)); - } - if (m_showAll || m_isHighlighted || all) + if (m_showAll || all) { + if (!m_flagIconURL.isEmpty() && !m_airlineIconURL.isEmpty()) + { + list.append(QString("
").arg(m_airlineIconURL).arg(m_flagIconURL)); + } + else + { + if (!m_flagIconURL.isEmpty()) { + list.append(QString("").arg(m_flagIconURL)); + } else if (!m_airlineIconURL.isEmpty()) { + list.append(QString("").arg(m_airlineIconURL)); + } + } + list.append(QString("ICAO: %1").arg(m_icaoHex)); + if (!m_callsign.isEmpty()) { + list.append(QString("Callsign: %1").arg(m_callsign)); + } if (m_aircraftInfo != nullptr) { - if (m_aircraftInfo->m_model.size() > 0) - { + if (!m_aircraftInfo->m_model.isEmpty()) { list.append(QString("Aircraft: %1").arg(m_aircraftInfo->m_model)); } } + if (!m_emitterCategory.isEmpty()) { + list.append(QString("Category: %1").arg(m_emitterCategory)); + } if (m_altitudeValid) { - if (m_gui->useSIUints()) - list.append(QString("Altitude: %1 (m)").arg(Units::feetToIntegerMetres(m_altitude))); + if (m_onSurface) + { + list.append(QString("Altitude: Surface")); + } else - list.append(QString("Altitude: %1 (ft)").arg(m_altitude)); + { + QString reference = m_altitudeGNSS ? "GNSS" : "Baro"; + if (m_gui->useSIUints()) { + list.append(QString("Altitude: %1 (m %2)").arg(Units::feetToIntegerMetres(m_altitude)).arg(reference)); + } else { + list.append(QString("Altitude: %1 (ft %2)").arg(m_altitude).arg(reference)); + } + } } if (m_speedValid) { - if (m_gui->useSIUints()) + if (m_gui->useSIUints()) { list.append(QString("%1: %2 (kph)").arg(m_speedTypeNames[m_speedType]).arg(Units::knotsToIntegerKPH(m_speed))); - else + } else { list.append(QString("%1: %2 (kn)").arg(m_speedTypeNames[m_speedType]).arg(m_speed)); + } } if (m_verticalRateValid) { @@ -213,12 +248,13 @@ QString Aircraft::getText(bool all) rate = m_verticalRate; units = QString("ft/min"); } - if (m_verticalRate == 0) + if (m_verticalRate == 0) { desc = "Level flight"; - else if (rate > 0) + } else if (rate > 0) { desc = QString("Climbing: %1 (%2)").arg(rate).arg(units); - else + } else { desc = QString("Descending: %1 (%2)").arg(rate).arg(units); + } list.append(QString(desc)); } if ((m_status.length() > 0) && m_status.compare("No emergency")) { @@ -270,7 +306,15 @@ QString Aircraft::getText(bool all) } } } - return list.join("\n"); + else if (!m_callsign.isEmpty()) + { + list.append(m_callsign); + } + else + { + list.append(m_icaoHex); + } + return list.join("
"); } QVariant AircraftModel::data(const QModelIndex &index, int role) const @@ -368,6 +412,14 @@ bool AircraftModel::setData(const QModelIndex &index, const QVariant& value, int return true; } +void AircraftModel::findOnMap(int index) +{ + if ((index < 0) || (index >= m_aircrafts.count())) { + return; + } + FeatureWebAPIUtils::mapFind(m_aircrafts[index]->m_icaoHex); +} + QVariant AirportModel::data(const QModelIndex &index, int role) const { int row = index.row(); @@ -626,31 +678,8 @@ void ADSBDemodGUI::updatePosition(Aircraft *aircraft) aircraft->m_elevation = m_azEl.getElevation(); aircraft->m_rangeItem->setText(QString::number(aircraft->m_range/1000.0, 'f', 1)); aircraft->m_azElItem->setText(QString("%1/%2").arg(std::round(aircraft->m_azimuth)).arg(std::round(aircraft->m_elevation))); - if (aircraft == m_trackAircraft) + if (aircraft == m_trackAircraft) { m_adsbDemod->setTarget(aircraft->targetName(), aircraft->m_azimuth, aircraft->m_elevation, aircraft->m_range); - - // Send to Map feature - MessagePipes& messagePipes = MainCore::instance()->getMessagePipes(); - QList *mapMessageQueues = messagePipes.getMessageQueues(m_adsbDemod, "mapitems"); - if (mapMessageQueues) - { - QList::iterator it = mapMessageQueues->begin(); - - for (; it != mapMessageQueues->end(); ++it) - { - SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); - swgMapItem->setName(new QString(QString("%1").arg(aircraft->m_icao, 0, 16))); - swgMapItem->setLatitude(aircraft->m_latitude); - swgMapItem->setLongitude(aircraft->m_longitude); - 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); - (*it)->push(msg); - } } } @@ -671,69 +700,161 @@ bool ADSBDemodGUI::updateLocalPosition(Aircraft *aircraft, double latitude, doub return true; } else + { + //qDebug() << "Local position out of range - calculated distance: " << m_azEl.getDistance(); return false; + } +} + +void ADSBDemodGUI::sendToMap(Aircraft *aircraft, QList *animations) +{ + // Send to Map feature + MessagePipes& messagePipes = MainCore::instance()->getMessagePipes(); + QList *mapMessageQueues = messagePipes.getMessageQueues(m_adsbDemod, "mapitems"); + if (mapMessageQueues) + { + QList::iterator it = mapMessageQueues->begin(); + + // Adjust altitude by airfield barometric elevation, so aircraft appears to + // take-off/land at correct point on runway + int altitudeFt = aircraft->m_altitude; + if (!aircraft->m_onSurface && !aircraft->m_altitudeGNSS) { + altitudeFt -= m_settings.m_airfieldElevation; + } + float altitudeM = Units::feetToMetres(altitudeFt); + + for (; it != mapMessageQueues->end(); ++it) + { + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + swgMapItem->setName(new QString(aircraft->m_icaoHex)); + swgMapItem->setLatitude(aircraft->m_latitude); + swgMapItem->setLongitude(aircraft->m_longitude); + swgMapItem->setAltitude(altitudeM); + swgMapItem->setPositionDateTime(new QString(aircraft->m_positionDateTime.toString(Qt::ISODateWithMs))); + swgMapItem->setFixedPosition(false); + swgMapItem->setImage(new QString(QString("qrc:///map/%1").arg(aircraft->getImage()))); + swgMapItem->setImageRotation(aircraft->m_heading); + swgMapItem->setText(new QString(aircraft->getText(true))); + if (!aircraft->m_aircraft3DModel.isEmpty()) { + swgMapItem->setModel(new QString(aircraft->m_aircraft3DModel)); + } else { + swgMapItem->setModel(new QString(aircraft->m_aircraftCat3DModel)); + } + swgMapItem->setLabel(new QString(aircraft->m_callsign)); + if (aircraft->m_headingValid) + { + swgMapItem->setOrientation(1); + swgMapItem->setHeading(aircraft->m_heading); + swgMapItem->setPitch(aircraft->m_pitch); + swgMapItem->setRoll(aircraft->m_roll); + swgMapItem->setOrientationDateTime(new QString(aircraft->m_positionDateTime.toString(Qt::ISODateWithMs))); + } + else + { + // Orient aircraft based on velocity calculated from position + swgMapItem->setOrientation(0); + } + swgMapItem->setModelAltitudeOffset(aircraft->m_modelAltitudeOffset); + swgMapItem->setLabelAltitudeOffset(aircraft->m_labelAltitudeOffset); + swgMapItem->setAltitudeReference(3); // CLIP_TO_GROUND so aircraft don't go under runway + swgMapItem->setAnimations(animations); // Does this need to be duplicated? + + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_adsbDemod, swgMapItem); + (*it)->push(msg); + } + } +} + +QString ADSBDemodGUI::getAirlineIconPath(const QString &operatorICAO) +{ + QString endPath = QString("/airlinelogos/%1.bmp").arg(operatorICAO); + // Try in user directory first, so they can customise + QString userIconPath = getDataDir() + endPath; + QFile file(userIconPath); + if (file.exists()) + { + return userIconPath; + } + else + { + // Try in resources + QString resourceIconPath = ":" + endPath; + QResource resource(resourceIconPath); + if (resource.isValid()) + { + return resourceIconPath; + } + } + return QString(); } // Try to find an airline logo based on ICAO QIcon *ADSBDemodGUI::getAirlineIcon(const QString &operatorICAO) { if (m_airlineIcons.contains(operatorICAO)) + { return m_airlineIcons.value(operatorICAO); + } else { QIcon *icon = nullptr; - QString endPath = QString("/airlinelogos/%1.bmp").arg(operatorICAO); - // Try in user directory first, so they can customise - QString userIconPath = getDataDir() + endPath; - QFile file(userIconPath); - if (file.exists()) + QString path = getAirlineIconPath(operatorICAO); + if (!path.isEmpty()) { - icon = new QIcon(userIconPath); + icon = new QIcon(path); m_airlineIcons.insert(operatorICAO, icon); } else { - // Try in resources - QResource resourceIconPath(QString(":%1").arg(endPath)); - if (resourceIconPath.isValid()) + if (!m_airlineMissingIcons.contains(operatorICAO)) { - icon = new QIcon(":" + endPath); - m_airlineIcons.insert(operatorICAO, icon); - } - else qDebug() << "ADSBDemodGUI: No airline logo for " << operatorICAO; + m_airlineMissingIcons.insert(operatorICAO, true); + } } return icon; } } +QString ADSBDemodGUI::getFlagIconPath(const QString &country) +{ + QString endPath = QString("/flags/%1.bmp").arg(country); + // Try in user directory first, so they can customise + QString userIconPath = getDataDir() + endPath; + QFile file(userIconPath); + if (file.exists()) + { + return userIconPath; + } + else + { + // Try in resources + QString resourceIconPath = ":" + endPath; + QResource resource(resourceIconPath); + if (resource.isValid()) + { + return resourceIconPath; + } + } + return QString(); +} + // Try to find an flag logo based on a country QIcon *ADSBDemodGUI::getFlagIcon(const QString &country) { if (m_flagIcons.contains(country)) + { return m_flagIcons.value(country); + } else { QIcon *icon = nullptr; - QString endPath = QString("/flags/%1.bmp").arg(country); - // Try in user directory first, so they can customise - QString userIconPath = getDataDir() + endPath; - QFile file(userIconPath); - if (file.exists()) + QString path = getFlagIconPath(country); + if (!path.isEmpty()) { - icon = new QIcon(userIconPath); + icon = new QIcon(path); m_flagIcons.insert(country, icon); } - else - { - // Try in resources - QResource resourceIconPath(QString(":%1").arg(endPath)); - if (resourceIconPath.isValid()) - { - icon = new QIcon(":" + endPath); - m_flagIcons.insert(country, icon); - } - } return icon; } } @@ -742,53 +863,57 @@ void ADSBDemodGUI::handleADSB( const QByteArray data, const QDateTime dateTime, float correlation, - float correlationOnes) + float correlationOnes, + bool updateModel) { - const char idMap[] = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ???????????????0123456789??????"; + const char idMap[] = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ????????????-??0123456789??????"; const QString categorySetA[] = { - "None", - "Light", - "Small", - "Large", - "High vortex", - "Heavy", - "High performance", - "Rotorcraft" + QStringLiteral("None"), + QStringLiteral("Light"), + QStringLiteral("Small"), + QStringLiteral("Large"), + QStringLiteral("High vortex"), + QStringLiteral("Heavy"), + QStringLiteral("High performance"), + QStringLiteral("Rotorcraft") }; const QString categorySetB[] = { - "None", - "Glider/sailplane", - "Lighter-than-air", - "Parachutist", - "Ultralight", - "Reserved", - "UAV", - "Space vehicle" + QStringLiteral("None"), + QStringLiteral("Glider/sailplane"), + QStringLiteral("Lighter-than-air"), + QStringLiteral("Parachutist"), + QStringLiteral("Ultralight"), + QStringLiteral("Reserved"), + QStringLiteral("UAV"), + QStringLiteral("Space vehicle") }; const QString categorySetC[] = { - "None", - "Emergency vehicle", - "Service vehicle", - "Ground obstruction", - "Cluster obstacle", - "Line obstacle", - "Reserved", - "Reserved" + QStringLiteral("None"), + QStringLiteral("Emergency vehicle"), + QStringLiteral("Service vehicle"), + QStringLiteral("Ground obstruction"), + QStringLiteral("Cluster obstacle"), + QStringLiteral("Line obstacle"), + QStringLiteral("Reserved"), + QStringLiteral("Reserved") }; const QString emergencyStatus[] = { - "No emergency", - "General emergency", - "Lifeguard/Medical", - "Minimum fuel", - "No communications", - "Unlawful interference", - "Downed aircraft", - "Reserved" + QStringLiteral("No emergency"), + QStringLiteral("General emergency"), + QStringLiteral("Lifeguard/Medical"), + QStringLiteral("Minimum fuel"), + QStringLiteral("No communications"), + QStringLiteral("Unlawful interference"), + QStringLiteral("Downed aircraft"), + QStringLiteral("Reserved") }; bool newAircraft = false; bool updatedCallsign = false; + bool prevAltitudeValid = false; + int prevAltitude; + int df = (data[0] >> 3) & ADS_B_DF_MASK; // Downlink format int ca = data[0] & 0x7; // Capability unsigned icao = ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff); // ICAO aircraft address @@ -799,6 +924,10 @@ void ADSBDemodGUI::handleADSB( { // Update existing aircraft info aircraft = m_aircraft.value(icao); + + // Save state that we later check to see if it has changed + prevAltitudeValid = aircraft->m_altitudeValid; + prevAltitude = aircraft->m_altitude; } else { @@ -806,12 +935,14 @@ void ADSBDemodGUI::handleADSB( newAircraft = true; aircraft = new Aircraft(this); aircraft->m_icao = icao; + aircraft->m_icaoHex = QString::number(aircraft->m_icao, 16); m_aircraft.insert(icao, aircraft); // Check for TIS-B addresses - if ((df == 18) && !((df == 18) && ((ca == 0) || (ca == 1) || (ca == 6)))) - aircraft->m_icaoItem->setText(QString("TIS-B %1").arg(aircraft->m_icao, 1, 16)); - else - aircraft->m_icaoItem->setText(QString("%1").arg(aircraft->m_icao, 1, 16)); + if ((df == 18) && !((df == 18) && ((ca == 0) || (ca == 1) || (ca == 6)))) { + aircraft->m_icaoItem->setText(QString("TIS-B %1").arg(aircraft->m_icaoHex)); + } else { + aircraft->m_icaoItem->setText(aircraft->m_icaoHex); + } ui->adsbData->setSortingEnabled(false); int row = ui->adsbData->rowCount(); ui->adsbData->setRowCount(row + 1); @@ -865,6 +996,10 @@ void ADSBDemodGUI::handleADSB( QIcon *icon = nullptr; if (aircraft->m_aircraftInfo->m_operatorICAO.size() > 0) { + aircraft->m_airlineIconURL = getAirlineIconPath(aircraft->m_aircraftInfo->m_operatorICAO); + if (aircraft->m_airlineIconURL.startsWith(':')) { + aircraft->m_airlineIconURL = "qrc://" + aircraft->m_airlineIconURL.mid(1); + } icon = getAirlineIcon(aircraft->m_aircraftInfo->m_operatorICAO); if (icon != nullptr) { @@ -908,6 +1043,10 @@ void ADSBDemodGUI::handleADSB( } if (flag != "") { + aircraft->m_flagIconURL = getFlagIconPath(flag); + if (aircraft->m_flagIconURL.startsWith(':')) { + aircraft->m_flagIconURL = "qrc://" + aircraft->m_flagIconURL.mid(1); + } icon = getFlagIcon(flag); if (icon != nullptr) { @@ -916,6 +1055,7 @@ void ADSBDemodGUI::handleADSB( } } } + get3DModel(aircraft); } } if (m_settings.m_autoResizeTableColumns) @@ -952,14 +1092,17 @@ void ADSBDemodGUI::handleADSB( { // Aircraft identification int ec = data[4] & 0x7; // Emitter category - if (tc == 4) + + QString prevEmitterCategory = aircraft->m_emitterCategory; + if (tc == 4) { aircraft->m_emitterCategory = categorySetA[ec]; - else if (tc == 3) + } else if (tc == 3) { aircraft->m_emitterCategory = categorySetB[ec]; - else if (tc == 2) + } else if (tc == 2) { aircraft->m_emitterCategory = categorySetC[ec]; - else - aircraft->m_emitterCategory = QString("Reserved"); + } else { + aircraft->m_emitterCategory = QStringLiteral("Reserved"); + } aircraft->m_emitterCategoryItem->setText(aircraft->m_emitterCategory); // Flight/callsign - Extract 8 6-bit characters from 6 8-bit bytes, MSB first @@ -1014,18 +1157,124 @@ void ADSBDemodGUI::handleADSB( { aircraft->m_flight = ""; } + + // Select 3D model based on category, if we don't already have one based on ICAO + if ( aircraft->m_aircraft3DModel.isEmpty() + && ( aircraft->m_aircraftCat3DModel.isEmpty() + || (prevEmitterCategory != aircraft->m_emitterCategory) + ) + ) + { + QString aircraftType; + + if (!aircraft->m_emitterCategory.compare("Heavy")) + { + aircraftType = "B744"; // Or B77W, B788, A350, A388 + } + else if (!aircraft->m_emitterCategory.compare("Large")) + { + aircraftType = "A320"; // Or B737 + } + else if (!aircraft->m_emitterCategory.compare("Small")) + { + aircraftType = "LJ45"; + } + else if (!aircraft->m_emitterCategory.compare("Rotorcraft")) + { + aircraft->m_aircraftCat3DModel = "helicopter.glb"; + aircraft->m_modelAltitudeOffset = 4.0f; + aircraft->m_labelAltitudeOffset = 4.0f; + } + else if (!aircraft->m_emitterCategory.compare("High performance")) + { + aircraft->m_aircraftCat3DModel = "f15.glb"; + aircraft->m_modelAltitudeOffset = 1.0f; + aircraft->m_labelAltitudeOffset = 6.0f; + } + else if (!aircraft->m_emitterCategory.compare("Light")) + { + aircraftType = "C172"; + } + else if (!aircraft->m_emitterCategory.compare("Ultralight")) + { + aircraft->m_aircraftCat3DModel = "ultralight.glb"; + aircraft->m_modelAltitudeOffset = 0.55f; + aircraft->m_labelAltitudeOffset = 0.75f; + } + else if (!aircraft->m_emitterCategory.compare("Glider/sailplane")) + { + aircraft->m_aircraftCat3DModel = "glider.glb"; + aircraft->m_modelAltitudeOffset = 1.0f; + aircraft->m_labelAltitudeOffset = 1.5f; + } + else if (!aircraft->m_emitterCategory.compare("Space vehicle")) + { + aircraft->m_aircraftCat3DModel = "atlas_v.glb"; + aircraft->m_labelAltitudeOffset = 16.0f; + } + else if (!aircraft->m_emitterCategory.compare("UAV")) + { + aircraft->m_aircraftCat3DModel = "drone.glb"; + aircraft->m_labelAltitudeOffset = 1.0f; + } + else if (!aircraft->m_emitterCategory.compare("Emergency vehicle")) + { + aircraft->m_aircraftCat3DModel = "fire_truck.glb"; + aircraft->m_modelAltitudeOffset = 0.3f; + aircraft->m_labelAltitudeOffset = 2.5f; + } + else if (!aircraft->m_emitterCategory.compare("Service vehicle")) + { + aircraft->m_aircraftCat3DModel = "airport_truck.glb"; + aircraft->m_labelAltitudeOffset = 3.0f; + } + else + { + aircraftType = "A320"; + } + + if (!aircraftType.isEmpty()) + { + if (aircraft->m_aircraftInfo) { + aircraft->m_aircraftCat3DModel = get3DModel(aircraftType, aircraft->m_aircraftInfo->m_operatorICAO); + } + if (aircraft->m_aircraftCat3DModel.isEmpty()) { + aircraft->m_aircraftCat3DModel = get3DModel(aircraftType, aircraft->m_callsign.left(3)); + } + if (aircraft->m_aircraftCat3DModel.isEmpty()) { + aircraft->m_aircraftCat3DModel = get3DModel(aircraftType); + } + if (m_modelAltitudeOffset.contains(aircraftType)) + { + aircraft->m_modelAltitudeOffset = m_modelAltitudeOffset.value(aircraftType); + aircraft->m_labelAltitudeOffset = m_labelAltitudeOffset.value(aircraftType); + } + } + } } else if (((tc >= 5) && (tc <= 18)) || ((tc >= 20) && (tc <= 22))) { - bool surfacePosition = (tc >= 5) && (tc <= 8); - if (surfacePosition) + bool wasOnSurface = aircraft->m_onSurface; + aircraft->m_onSurface = (tc >= 5) && (tc <= 8); + + if (wasOnSurface != aircraft->m_onSurface) + { + // Can't mix CPR values used on surface and those that are airbourne + aircraft->m_cprValid[0] = false; + aircraft->m_cprValid[1] = false; + } + + if (aircraft->m_onSurface) { // Surface position - // Set altitude to 0, if we're on the surface - // Actual altitude may of course depend on airport elevation + // There are a few airports that are below 0 MSL + // https://en.wikipedia.org/wiki/List_of_lowest_airports + // So we set altitude to a negative value here, which should + // then get clipped to actual terrain elevation in 3D map aircraft->m_altitudeValid = true; - aircraft->m_altitudeItem->setData(Qt::DisplayRole, 0); + aircraft->m_altitude = -200; + aircraft->m_altitudeItem->setData(Qt::DisplayRole, "Surface"); int movement = ((data[4] & 0x7) << 4) | ((data[5] >> 4) & 0xf); if (movement == 0) @@ -1039,50 +1288,52 @@ void ADSBDemodGUI::handleADSB( // Aircraft stopped aircraft->m_speedValid = true; aircraft->m_speedItem->setData(Qt::DisplayRole, 0); + aircraft->m_speed = 0.0; } else if ((movement >= 2) && (movement <= 123)) { - // float base, step; // In knts - // int adjust; - // if ((movement >= 2) && (movement <= 8)) - // { - // base = 0.125f; - // step = 0.125f; - // adjust = 2; - // } - // else if ((movement >= 9) && (movement <= 12)) - // { - // base = 1.0f; - // step = 0.25f; - // adjust = 9; - // } - // else if ((movement >= 13) && (movement <= 38)) - // { - // base = 2.0f; - // step = 0.5f; - // adjust = 13; - // } - // else if ((movement >= 39) && (movement <= 93)) - // { - // base = 15.0f; - // step = 1.0f; - // adjust = 39; - // } - // else if ((movement >= 94) && (movement <= 108)) - // { - // base = 70.0f; - // step = 2.0f; - // adjust = 94; - // } - // else - // { - // base = 100.0f; - // step = 5.0f; - // adjust = 109; - // } + float base, step; // In knts + int adjust; + if ((movement >= 2) && (movement <= 8)) + { + base = 0.125f; + step = 0.125f; + adjust = 2; + } + else if ((movement >= 9) && (movement <= 12)) + { + base = 1.0f; + step = 0.25f; + adjust = 9; + } + else if ((movement >= 13) && (movement <= 38)) + { + base = 2.0f; + step = 0.5f; + adjust = 13; + } + else if ((movement >= 39) && (movement <= 93)) + { + base = 15.0f; + step = 1.0f; + adjust = 39; + } + else if ((movement >= 94) && (movement <= 108)) + { + base = 70.0f; + step = 2.0f; + adjust = 94; + } + else + { + base = 100.0f; + step = 5.0f; + adjust = 109; + } + aircraft->m_speed = base + (movement - adjust) * step; aircraft->m_speedType = Aircraft::GS; aircraft->m_speedValid = true; - aircraft->m_speedItem->setData(Qt::DisplayRole, m_settings.m_siUnits ? Units::knotsToIntegerKPH(aircraft->m_speed) : (int)std::round(aircraft->m_speed)); + aircraft->m_speedItem->setData(Qt::DisplayRole, m_settings.m_siUnits ? Units::knotsToIntegerKPH(aircraft->m_speed) : (int)std::round(aircraft->m_speed)); } else if (movement == 124) { @@ -1094,22 +1345,62 @@ void ADSBDemodGUI::handleADSB( int groundTrackValue = ((data[5] & 0x7) << 4) | ((data[6] >> 4) & 0xf); if (groundTrackStatus) { - aircraft->m_heading = std::round((groundTrackValue * 360.0/128.0)); + aircraft->m_heading = groundTrackValue * 360.0/128.0; aircraft->m_headingValid = true; - aircraft->m_headingItem->setData(Qt::DisplayRole, aircraft->m_heading); + aircraft->m_headingItem->setData(Qt::DisplayRole, std::round(aircraft->m_heading)); } } else if (((tc >= 9) && (tc <= 18)) || ((tc >= 20) && (tc <= 22))) { // Airbourne position (9-18 baro, 20-22 GNSS) int alt = ((data[5] & 0xff) << 4) | ((data[6] >> 4) & 0xf); // Altitude - int n = ((alt >> 1) & 0x7f0) | (alt & 0xf); - int alt_ft = n * ((alt & 0x10) ? 25 : 100) - 1000; + int q = (alt & 0x10) != 0; + int n = ((alt >> 1) & 0x7f0) | (alt & 0xf); // Remove Q-bit + int alt_ft; + if (q == 1) + { + alt_ft = n * ((alt & 0x10) ? 25 : 100) - 1000; + } + else + { + // https://en.wikipedia.org/wiki/Gillham_code + int c1 = (n >> 10) & 1; + int a1 = (n >> 9) & 1; + int c2 = (n >> 8) & 1; + int a2 = (n >> 7) & 1; + int c4 = (n >> 6) & 1; + int a4 = (n >> 5) & 1; + int b1 = (n >> 4) & 1; + int b2 = (n >> 3) & 1; + int d2 = (n >> 2) & 1; + int b4 = (n >> 1) & 1; + int d4 = n & 1; + + int n500 = grayToBinary((d2 << 7) | (d4 << 6) | (a1 << 5) | (a2 << 4) | (a4 << 3) | (b1 << 2) | (b2 << 1) | b4, 4); + int n100 = grayToBinary((c1 << 2) | (c2 << 1) | c4, 3) - 1; + + if (n100 == 6) { + n100 = 4; + } + if (n500 %2 != 0) { + n100 = 4 - n100; + } + + alt_ft = -1200 + n500*500 + n100*100; + } aircraft->m_altitude = alt_ft; - aircraft->m_altitudeValid = true; + aircraft->m_altitudeValid = alt != 0; + aircraft->m_altitudeGNSS = ((tc >= 20) && (tc <= 22)); // setData rather than setText so it sorts numerically aircraft->m_altitudeItem->setData(Qt::DisplayRole, m_settings.m_siUnits ? Units::feetToIntegerMetres(aircraft->m_altitude) : aircraft->m_altitude); + + // Assume runway elevation is at first reported airboune altitude + if (wasOnSurface) + { + aircraft->m_runwayAltitude = aircraft->m_altitude; + aircraft->m_runwayAltitudeValid = true; + } } int f = (data[6] >> 2) & 1; // CPR odd/even frame - should alternate every 0.2s @@ -1126,10 +1417,12 @@ void ADSBDemodGUI::handleADSB( // See also: https://mode-s.org/decode/adsb/airborne-position.html // For global decoding, we need both odd and even frames // We also need to check that both frames aren't greater than 10s apart in time (C.2.6.7), otherwise position may be out by ~10deg + // I've reduced this to 8.5s, as problems have been seen where times are just 9s apart. This may be because + // our timestamps aren't accurate, as the times are generated when packets are decoded on buffered data. // We could compare global + local methods to see if the positions are sensible if (aircraft->m_cprValid[0] && aircraft->m_cprValid[1] - && (std::abs(aircraft->m_cprTime[0].toSecsSinceEpoch() - aircraft->m_cprTime[1].toSecsSinceEpoch()) < 10) - && !surfacePosition) + && (std::abs(aircraft->m_cprTime[0].toMSecsSinceEpoch() - aircraft->m_cprTime[1].toMSecsSinceEpoch()) <= 8500) + && !aircraft->m_onSurface) { // Global decode using odd and even frames (C.2.6) @@ -1178,6 +1471,7 @@ void ADSBDemodGUI::handleADSB( aircraft->m_latitudeItem->setData(Qt::DisplayRole, aircraft->m_latitude); aircraft->m_longitude = longitude; aircraft->m_longitudeItem->setData(Qt::DisplayRole, aircraft->m_longitude); + aircraft->m_positionDateTime = dateTime; QGeoCoordinate coord(aircraft->m_latitude, aircraft->m_longitude, aircraft->m_altitude); aircraft->m_coordinates.push_back(QVariant::fromValue(coord)); updatePosition(aircraft); @@ -1185,7 +1479,7 @@ void ADSBDemodGUI::handleADSB( } else { - qDebug() << "ADSBDemodGUI::handleADSB: Invalid latitude " << latitude << " for " << QString("%1").arg(aircraft->m_icao, 1, 16) + qDebug() << "ADSBDemodGUI::handleADSB: Invalid latitude " << latitude << " for " << QString("%1").arg(aircraft->m_icaoHex) << " m_cprLat[0] " << aircraft->m_cprLat[0] << " m_cprLat[1] " << aircraft->m_cprLat[1]; aircraft->m_cprValid[0] = false; @@ -1198,7 +1492,7 @@ void ADSBDemodGUI::handleADSB( // Only valid if airbourne within 180nm/333km (C.2.6.4) or 45nm for surface // Caclulate latitude - const double maxDeg = surfacePosition ? 90.0 : 360.0; + const double maxDeg = aircraft->m_onSurface ? 90.0 : 360.0; const double dLatEven = maxDeg/60.0; const double dLatOdd = maxDeg/59.0; double dLat = f ? dLatOdd : dLatEven; @@ -1227,12 +1521,13 @@ void ADSBDemodGUI::handleADSB( int m = std::floor(m_azEl.getLocationSpherical().m_longitude/dLong) + std::floor(modulus(m_azEl.getLocationSpherical().m_longitude, dLong)/dLong - aircraft->m_cprLong[f] + 0.5); longitude = dLong * (m + aircraft->m_cprLong[f]); - if (updateLocalPosition(aircraft, latitude, longitude, surfacePosition)) + if (updateLocalPosition(aircraft, latitude, longitude, aircraft->m_onSurface)) { aircraft->m_latitude = latitude; aircraft->m_latitudeItem->setData(Qt::DisplayRole, aircraft->m_latitude); aircraft->m_longitude = longitude; aircraft->m_longitudeItem->setData(Qt::DisplayRole, aircraft->m_longitude); + aircraft->m_positionDateTime = dateTime; QGeoCoordinate coord(aircraft->m_latitude, aircraft->m_longitude, aircraft->m_altitude); aircraft->m_coordinates.push_back(QVariant::fromValue(coord)); } @@ -1252,29 +1547,34 @@ void ADSBDemodGUI::handleADSB( int v_we; int v_sn; - int v; - int h; + float v; + float h; - if (s_ew) + if (s_ew) { v_we = -1 * (v_ew - 1); - else + } else { v_we = v_ew - 1; - if (s_ns) + } + if (s_ns) { v_sn = -1 * (v_ns - 1); - else + } else { v_sn = v_ns - 1; - v = (int)std::sqrt(v_we*v_we + v_sn*v_sn); + } + v = std::round(std::sqrt(v_we*v_we + v_sn*v_sn)); h = std::atan2(v_we, v_sn) * 360.0/(2.0*M_PI); - if (h < 0) - h += 360; + if (h < 0.0) { + h += 360.0; + } aircraft->m_heading = h; aircraft->m_headingValid = true; + aircraft->m_headingDateTime = dateTime; aircraft->m_speed = v; aircraft->m_speedType = Aircraft::GS; aircraft->m_speedValid = true; - aircraft->m_headingItem->setData(Qt::DisplayRole, aircraft->m_heading); + aircraft->m_headingItem->setData(Qt::DisplayRole, std::round(aircraft->m_heading)); aircraft->m_speedItem->setData(Qt::DisplayRole, m_settings.m_siUnits ? Units::knotsToIntegerKPH(aircraft->m_speed) : aircraft->m_speed); + aircraft->m_orientationDateTime = dateTime; } else { @@ -1285,10 +1585,12 @@ void ADSBDemodGUI::handleADSB( { aircraft->m_heading = hdg/1024.0f*360.0f; aircraft->m_headingValid = true; - aircraft->m_headingItem->setData(Qt::DisplayRole, aircraft->m_heading); + aircraft->m_headingDateTime = dateTime; + aircraft->m_headingItem->setData(Qt::DisplayRole, std::round(aircraft->m_heading)); + aircraft->m_orientationDateTime = dateTime; } - int as_t = (data[7] >> 7) & 1; // Airspeed type + int as_t = (data[7] >> 7) & 1; // Airspeed type int as = ((data[7] & 0x7f) << 3) | ((data[8] >> 5) & 0x7); // Airspeed aircraft->m_speed = as; @@ -1343,7 +1645,16 @@ void ADSBDemodGUI::handleADSB( // Update aircraft in map if (aircraft->m_positionValid) { - m_aircraftModel.aircraftUpdated(aircraft); + // Check to see if we need to start any animations + QList *animations = animate(dateTime, aircraft, prevAltitudeValid, prevAltitude); + + // Update map displayed in channel + if (updateModel) { + m_aircraftModel.aircraftUpdated(aircraft); + } + + // Send to Map feature + sendToMap(aircraft, animations); } } else if (df == 18) @@ -1361,6 +1672,333 @@ void ADSBDemodGUI::handleADSB( } } +QList * ADSBDemodGUI::animate(QDateTime dateTime, Aircraft *aircraft, bool prevAltitudeValid, int prevAltitude) +{ + QList *animations = new QList(); + + const int gearDownSpeed = 150; + const int gearUpAltitude = 200; + const int gearUpVerticalRate = 1000; + const int accelerationHeight = 1500; + const int flapsRetractAltitude = 2000; + const int flapsCleanSpeed = 200; + const int flapsFullSpeed = 170; + + bool debug = false; + + // Landing gear should be down when on surface + // Check speed in case we get a mixture of surface and airbourne positions + // during take-off + if ( aircraft->m_onSurface + && !aircraft->m_gearDown + && ( (aircraft->m_speedValid && (aircraft->m_speed < 80)) + || !aircraft->m_speedValid + ) + ) + { + if (debug) { + qDebug() << "Gear down as on surface " << aircraft->m_icaoHex; + } + animations->append(gearAnimation(dateTime, false)); + aircraft->m_gearDown = true; + } + + // Flaps when on the surface + if (aircraft->m_onSurface && aircraft->m_speedValid) + { + if ((aircraft->m_speed <= 20) && (aircraft->m_flaps != 0.0)) + { + // No flaps when stationary / taxiing + if (debug) { + qDebug() << "Parking flaps " << aircraft->m_icaoHex; + } + animations->append(flapsAnimation(dateTime, aircraft->m_flaps, 0.0)); + animations->append(slatsAnimation(dateTime, true)); + aircraft->m_flaps = 0.0; + } + else if ((aircraft->m_speed >= 30) && (aircraft->m_flaps < 0.25)) + { + // Flaps for takeoff + if (debug) { + qDebug() << "Takeoff flaps " << aircraft->m_icaoHex; + } + animations->append(flapsAnimation(dateTime, aircraft->m_flaps, 0.25)); + animations->append(slatsAnimation(dateTime, false)); + aircraft->m_flaps = 0.25; + } + } + + // Pitch up on take-off + if ( aircraft->m_gearDown + && !aircraft->m_onSurface + && ( (aircraft->m_verticalRateValid && (aircraft->m_verticalRate > 300)) + || (aircraft->m_runwayAltitudeValid && (aircraft->m_altitude > (aircraft->m_runwayAltitude + gearUpAltitude/2))) + ) + ) + { + if (debug) { + qDebug() << "Pitch up " << aircraft->m_icaoHex; + } + aircraft->m_pitch = 5.0; + } + + // Retract landing gear after take-off + if ( aircraft->m_gearDown + && !aircraft->m_onSurface + && ( (aircraft->m_verticalRateValid && (aircraft->m_verticalRate > 1000)) + || (aircraft->m_runwayAltitudeValid && (aircraft->m_altitude > (aircraft->m_runwayAltitude + gearUpAltitude))) + ) + ) + { + if (debug) { + qDebug() << "Gear up " << aircraft->m_icaoHex + << " VR " << (aircraft->m_verticalRateValid && (aircraft->m_verticalRate > gearUpVerticalRate)) + << " Alt " << (aircraft->m_runwayAltitudeValid && (aircraft->m_altitude > (aircraft->m_runwayAltitude + gearUpAltitude))) + << "m_altitude " << aircraft->m_altitude << " aircraft->m_runwayAltitude " << aircraft->m_runwayAltitude; + } + aircraft->m_pitch = 10.0; + animations->append(gearAnimation(dateTime.addSecs(2), true)); + aircraft->m_gearDown = false; + } + + // Reduce pitch at acceleration height + if ( (aircraft->m_flaps > 0.0) + && (aircraft->m_runwayAltitudeValid && (aircraft->m_altitude > (aircraft->m_runwayAltitude + accelerationHeight))) + ) + { + aircraft->m_pitch = 5.0; + } + + // Retract flaps/slats after take-off + // Should be after acceleration altitude (1500-3000ft AAL) + // And before max speed for flaps is reached (215knt for A320, 255KIAS for 777) + if ( (aircraft->m_flaps > 0.0) + && ( (aircraft->m_runwayAltitudeValid && (aircraft->m_altitude > (aircraft->m_runwayAltitude + flapsRetractAltitude))) + || (aircraft->m_speedValid && (aircraft->m_speed > flapsCleanSpeed)) + ) + ) + { + if (debug) { + qDebug() << "Retract flaps " << aircraft->m_icaoHex + << " Spd " << (aircraft->m_speedValid && (aircraft->m_speed > flapsCleanSpeed)) + << " Alt " << (aircraft->m_runwayAltitudeValid && (aircraft->m_altitude > (aircraft->m_runwayAltitude + flapsRetractAltitude))); + } + animations->append(flapsAnimation(dateTime, aircraft->m_flaps, 0.0)); + animations->append(slatsAnimation(dateTime, true)); + aircraft->m_flaps = 0.0; + // Clear runway information + aircraft->m_runwayAltitudeValid = false; + aircraft->m_runwayAltitude = 0.0; + } + + // Extend flaps for approach and landing + // We don't know airport elevation, so just base on speed and descent rate + // Vertical rate can go negative during take-off, so we check m_runwayAltitudeValid + if (!aircraft->m_onSurface + && !aircraft->m_runwayAltitudeValid + && (aircraft->m_verticalRateValid && (aircraft->m_verticalRate < 0)) + && aircraft->m_speedValid + ) + { + if ((aircraft->m_speed < flapsCleanSpeed) && (aircraft->m_flaps < 0.25)) + { + // Extend flaps for approach + if (debug) { + qDebug() << "Extend flaps for approach" << aircraft->m_icaoHex; + } + animations->append(flapsAnimation(dateTime, aircraft->m_flaps, 0.25)); + //animations->append(slatsAnimation(dateTime, false)); + aircraft->m_flaps = 0.25; + aircraft->m_pitch = 1.0; + } + } + + // Gear down for landing + // We don't know airport elevation, so just base on speed and descent rate + if (!aircraft->m_gearDown + && !aircraft->m_onSurface + && !aircraft->m_runwayAltitudeValid + && (aircraft->m_verticalRateValid && (aircraft->m_verticalRate < 0)) + && (aircraft->m_speedValid && (aircraft->m_speed < gearDownSpeed)) + ) + { + if (debug) { + qDebug() << "Flaps/Gear down for landing " << aircraft->m_icaoHex; + } + animations->append(flapsAnimation(dateTime, aircraft->m_flaps, 0.5)); + animations->append(slatsAnimation(dateTime, false)); + animations->append(gearAnimation(dateTime.addSecs(8), false)); + animations->append(flapsAnimation(dateTime.addSecs(16), 0.5, 1.0)); + aircraft->m_gearDown = true; + aircraft->m_flaps = 1.0; + aircraft->m_pitch = 3.0; + } + + // Engine control + if (aircraft->m_emitterCategory == "Rotorcraft") + { + // Helicopter rotors + if (!aircraft->m_rotorStarted && !aircraft->m_onSurface) + { + // Start rotors + if (debug) { + qDebug() << "Start rotors " << aircraft->m_icaoHex; + } + animations->append(rotorAnimation(dateTime, false)); + aircraft->m_rotorStarted = true; + } + else if (aircraft->m_rotorStarted && aircraft->m_onSurface) + { + if (debug) { + qDebug() << "Stop rotors " << aircraft->m_icaoHex; + } + animations->append(rotorAnimation(dateTime, true)); + aircraft->m_rotorStarted = false; + } + } + else + { + // Propellors + if (!aircraft->m_engineStarted && aircraft->m_speedValid && (aircraft->m_speed > 0)) + { + if (debug) { + qDebug() << "Start engines " << aircraft->m_icaoHex; + } + animations->append(engineAnimation(dateTime, 1, false)); + animations->append(engineAnimation(dateTime, 2, false)); + aircraft->m_engineStarted = true; + } + else if (aircraft->m_engineStarted && aircraft->m_speedValid && (aircraft->m_speed == 0)) + { + if (debug) { + qDebug() << "Stop engines " << aircraft->m_icaoHex; + } + animations->append(engineAnimation(dateTime, 1, true)); + animations->append(engineAnimation(dateTime, 2, true)); + aircraft->m_engineStarted = false; + } + } + + // Estimate pitch, so it looks a little more realistic + if (aircraft->m_onSurface) + { + // Check speed so we don't set pitch to 0 immediately on touch-down + // Should probably record time of touch-down and reduce over time + if (aircraft->m_speedValid) + { + if (aircraft->m_speed < 80) { + aircraft->m_pitch = 0.0; + } else if ((aircraft->m_speed < 130) && (aircraft->m_pitch >= 2)) { + aircraft->m_pitch = 1; + } + } + } + else if ((aircraft->m_flaps < 0.25) && aircraft->m_verticalRateValid) + { + // In climb/descent + aircraft->m_pitch = std::abs(aircraft->m_verticalRate / 400.0); + } + + // Estimate some roll + if (aircraft->m_onSurface + || (aircraft->m_runwayAltitudeValid && (aircraft->m_altitude < (aircraft->m_runwayAltitude + accelerationHeight)))) + { + aircraft->m_roll = 0.0; + } + else if (aircraft->m_headingValid) + { + // Really need to use more data points for this - or better yet, get it from Mode-S frames + if (aircraft->m_prevHeadingDateTime.isValid()) + { + qint64 msecs = aircraft->m_prevHeadingDateTime.msecsTo(aircraft->m_headingDateTime); + if (msecs > 0) + { + float headingDiff = fmod(aircraft->m_heading - aircraft->m_prevHeading + 540.0, 360.0) - 180.0; + float roll = headingDiff / (msecs / 1000.0); + //qDebug() << "Heading Diff " << headingDiff << " msecs " << msecs << " roll " << roll; + roll = std::min(roll, 15.0f); + roll = std::max(roll, -15.0f); + aircraft->m_roll = roll; + } + } + aircraft->m_prevHeadingDateTime = aircraft->m_headingDateTime; + aircraft->m_prevHeading = aircraft->m_heading; + } + + return animations; +} + +SWGSDRangel::SWGMapAnimation *ADSBDemodGUI::gearAnimation(QDateTime startDateTime, bool up) +{ + // Gear up/down + SWGSDRangel::SWGMapAnimation *animation = new SWGSDRangel::SWGMapAnimation(); + animation->setName(new QString("libxplanemp/controls/gear_ratio")); + animation->setStartDateTime(new QString(startDateTime.toString(Qt::ISODateWithMs))); + animation->setReverse(up); + animation->setLoop(0); + animation->setDuration(5); + animation->setMultiplier(0.2); + return animation; +} + +SWGSDRangel::SWGMapAnimation *ADSBDemodGUI::flapsAnimation(QDateTime startDateTime, float currentFlaps, float flaps) +{ + // Extend / retract flags + bool retract = flaps < currentFlaps; + SWGSDRangel::SWGMapAnimation *animation = new SWGSDRangel::SWGMapAnimation(); + animation->setName(new QString("libxplanemp/controls/flap_ratio")); + animation->setStartDateTime(new QString(startDateTime.toString(Qt::ISODateWithMs))); + animation->setReverse(retract); + animation->setLoop(0); + animation->setDuration(5*std::abs(flaps-currentFlaps)); + animation->setMultiplier(0.2); + if (retract) { + animation->setStartOffset(1.0 - currentFlaps); + } else { + animation->setStartOffset(currentFlaps); + } + return animation; +} + +SWGSDRangel::SWGMapAnimation *ADSBDemodGUI::slatsAnimation(QDateTime startDateTime, bool retract) +{ + // Extend / retract slats + SWGSDRangel::SWGMapAnimation *animation = new SWGSDRangel::SWGMapAnimation(); + animation->setName(new QString("libxplanemp/controls/slat_ratio")); + animation->setStartDateTime(new QString(startDateTime.toString(Qt::ISODateWithMs))); + animation->setReverse(retract); + animation->setLoop(0); + animation->setDuration(5); + animation->setMultiplier(0.2); + return animation; +} + +SWGSDRangel::SWGMapAnimation *ADSBDemodGUI::rotorAnimation(QDateTime startDateTime, bool stop) +{ + // Turn rotors in helicopter.glb model + SWGSDRangel::SWGMapAnimation *animation = new SWGSDRangel::SWGMapAnimation(); + animation->setName(new QString("Take 001")); + animation->setStartDateTime(new QString(startDateTime.toString(Qt::ISODateWithMs))); + animation->setReverse(false); + animation->setLoop(true); + animation->setMultiplier(1); + animation->setStop(stop); + return animation; +} + +SWGSDRangel::SWGMapAnimation *ADSBDemodGUI::engineAnimation(QDateTime startDateTime, int engine, bool stop) +{ + // Turn propellors + SWGSDRangel::SWGMapAnimation *animation = new SWGSDRangel::SWGMapAnimation(); + animation->setName(new QString(QString("libxplanemp/engines/engine_rotation_angle_deg%1").arg(engine))); + animation->setStartDateTime(new QString(startDateTime.toString(Qt::ISODateWithMs))); + animation->setReverse(false); + animation->setLoop(true); + animation->setMultiplier(1); + animation->setStop(stop); + return animation; +} + void ADSBDemodGUI::checkStaticNotification(Aircraft *aircraft) { for (int i = 0; i < m_settings.m_notificationSettings.size(); i++) @@ -1539,10 +2177,11 @@ bool ADSBDemodGUI::handleMessage(const Message& message) if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; - bool srTooLow = notif.getSampleRate() < 2000000; + int sr = notif.getSampleRate(); + bool srTooLow = sr < 2000000; ui->warning->setVisible(srTooLow); if (srTooLow) { - ui->warning->setText("Sample rate must be >= 2000000"); + ui->warning->setText(QString("Sample rate must be >= 2000000. Currently %1").arg(sr)); } else { ui->warning->setText(""); } @@ -1556,7 +2195,8 @@ if (DSPSignalNotification::match(message)) report.getData(), report.getDateTime(), report.getPreambleCorrelation(), - report.getCorrelationOnes()); + report.getCorrelationOnes(), + true); return true; } else if (ADSBDemodReport::MsgReportDemodStats::match(message)) @@ -1702,6 +2342,136 @@ void ADSBDemodGUI::on_flightInfo_clicked() } } +// Find highlighed aircraft on Map Feature +void ADSBDemodGUI::on_findOnMapFeature_clicked() +{ + QModelIndexList indexList = ui->adsbData->selectionModel()->selectedRows(); + if (!indexList.isEmpty()) + { + int row = indexList.at(0).row(); + QString icao = ui->adsbData->item(row, 0)->text(); + FeatureWebAPIUtils::mapFind(icao); + } +} + +// Find aircraft on channel map +void ADSBDemodGUI::findOnChannelMap(Aircraft *aircraft) +{ + if (aircraft->m_positionValid) + { + QQuickItem *item = ui->map->rootObject(); + QObject *object = item->findChild("map"); + if(object != NULL) + { + QGeoCoordinate geocoord = object->property("center").value(); + geocoord.setLatitude(aircraft->m_latitude); + geocoord.setLongitude(aircraft->m_longitude); + object->setProperty("center", QVariant::fromValue(geocoord)); + } + } +} + +void ADSBDemodGUI::adsbData_customContextMenuRequested(QPoint pos) +{ + QTableWidgetItem *item = ui->adsbData->itemAt(pos); + if (item) + { + int row = item->row(); + int icao = ui->adsbData->item(row, 0)->text().toInt(nullptr, 16); + Aircraft *aircraft = nullptr; + if (m_aircraft.contains(icao)) { + aircraft = m_aircraft.value(icao); + } + QString icaoHex = QString("%1").arg(icao, 1, 16); + + QMenu* tableContextMenu = new QMenu(ui->adsbData); + connect(tableContextMenu, &QMenu::aboutToHide, tableContextMenu, &QMenu::deleteLater); + + // Copy current cell + + QAction* copyAction = new QAction("Copy", tableContextMenu); + const QString text = item->text(); + connect(copyAction, &QAction::triggered, this, [text]()->void { + QClipboard *clipboard = QGuiApplication::clipboard(); + clipboard->setText(text); + }); + tableContextMenu->addAction(copyAction); + tableContextMenu->addSeparator(); + + // View aircraft on various websites + + QAction* planeSpottersAction = new QAction("View aircraft on planespotters.net...", tableContextMenu); + connect(planeSpottersAction, &QAction::triggered, this, [icao]()->void { + QString icaoUpper = QString("%1").arg(icao, 1, 16).toUpper(); + QDesktopServices::openUrl(QUrl(QString("https://www.planespotters.net/hex/%1").arg(icaoUpper))); + }); + tableContextMenu->addAction(planeSpottersAction); + + QAction* adsbExchangeAction = new QAction("View aircraft on adsbexchange.net...", tableContextMenu); + connect(adsbExchangeAction, &QAction::triggered, this, [icaoHex]()->void { + QDesktopServices::openUrl(QUrl(QString("https://globe.adsbexchange.com/?icao=%1").arg(icaoHex))); + }); + tableContextMenu->addAction(adsbExchangeAction); + + QAction* viewOpenSkyAction = new QAction("View aircraft on opensky-network.org...", tableContextMenu); + connect(viewOpenSkyAction, &QAction::triggered, this, [icaoHex]()->void { + QDesktopServices::openUrl(QUrl(QString("https://opensky-network.org/aircraft-profile?icao24=%1").arg(icaoHex))); + }); + tableContextMenu->addAction(viewOpenSkyAction); + + if (!aircraft->m_callsign.isEmpty()) + { + QAction* flightRadarAction = new QAction("View flight on flightradar24.net...", tableContextMenu); + connect(flightRadarAction, &QAction::triggered, this, [aircraft]()->void { + QDesktopServices::openUrl(QUrl(QString("https://www.flightradar24.com/%1").arg(aircraft->m_callsign))); + }); + tableContextMenu->addAction(flightRadarAction); + } + + tableContextMenu->addSeparator(); + + // Edit aircraft + + if (!aircraft->m_aircraftInfo) + { + QAction* addOpenSkyAction = new QAction("Add aircraft to opensky-network.org...", tableContextMenu); + connect(addOpenSkyAction, &QAction::triggered, this, []()->void { + QDesktopServices::openUrl(QUrl(QString("https://opensky-network.org/edit-aircraft-profile"))); + }); + tableContextMenu->addAction(addOpenSkyAction); + } + else + { + + QAction* editOpenSkyAction = new QAction("Edit aircraft on opensky-network.org...", tableContextMenu); + connect(editOpenSkyAction, &QAction::triggered, this, [icaoHex]()->void { + QDesktopServices::openUrl(QUrl(QString("https://opensky-network.org/edit-aircraft-profile?icao24=%1").arg(icaoHex))); + }); + tableContextMenu->addAction(editOpenSkyAction); + } + + // Find on Map + if (aircraft->m_positionValid) + { + tableContextMenu->addSeparator(); + + QAction* findChannelMapAction = new QAction("Find on ADS-B map", tableContextMenu); + connect(findChannelMapAction, &QAction::triggered, this, [this, aircraft]()->void { + findOnChannelMap(aircraft); + }); + tableContextMenu->addAction(findChannelMapAction); + + QAction* findMapFeatureAction = new QAction("Find on feature map", tableContextMenu); + connect(findMapFeatureAction, &QAction::triggered, this, [icaoHex]()->void { + FeatureWebAPIUtils::mapFind(icaoHex); + }); + tableContextMenu->addAction(findMapFeatureAction); + } + + tableContextMenu->popup(ui->adsbData->viewport()->mapToGlobal(pos)); + } +} + void ADSBDemodGUI::on_adsbData_cellClicked(int row, int column) { (void) column; @@ -1743,15 +2513,7 @@ void ADSBDemodGUI::on_adsbData_cellDoubleClicked(int row, int column) // Center map view on aircraft if it has a valid position if (aircraft->m_positionValid) { - QQuickItem *item = ui->map->rootObject(); - QObject *object = item->findChild("map"); - if(object != NULL) - { - QGeoCoordinate geocoord = object->property("center").value(); - geocoord.setLatitude(aircraft->m_latitude); - geocoord.setLongitude(aircraft->m_longitude); - object->setProperty("center", QVariant::fromValue(geocoord)); - } + findOnChannelMap(aircraft); } } } @@ -1823,7 +2585,7 @@ void ADSBDemodGUI::on_getOSNDB_clicked() // Don't try to download while already in progress if (m_progressDialog == nullptr) { - QString osnDBFilename = getOSNDBFilename(); + QString osnDBFilename = getOSNDBZipFilename(); if (confirmDownload(osnDBFilename)) { // Download Opensky network database to a file @@ -1898,6 +2660,11 @@ QString ADSBDemodGUI::getAirportFrequenciesDBFilename() return getDataDir() + "/airportFrequenciesDatabase.csv"; } +QString ADSBDemodGUI::getOSNDBZipFilename() +{ + return getDataDir() + "/aircraftDatabase.zip"; +} + QString ADSBDemodGUI::getOSNDBFilename() { return getDataDir() + "/aircraftDatabase.csv"; @@ -1966,9 +2733,32 @@ void ADSBDemodGUI::downloadFinished(const QString& filename, bool success) bool closeDialog = true; if (success) { - if (filename == getOSNDBFilename()) + if (filename == getOSNDBZipFilename()) { - readOSNDB(filename); + // Extract .csv file from .zip file + QZipReader reader(filename); + QByteArray database = reader.fileData("media/data/samples/metadata/aircraftDatabase.csv"); + if (database.size() > 0) + { + QFile file(getOSNDBFilename()); + if (file.open(QIODevice::WriteOnly)) + { + file.write(database); + file.close(); + } + else + { + qWarning() << "ADSBDemodGUI::downloadFinished - Failed to open " << file.fileName() << " for writing"; + } + } + else + { + qWarning() << "ADSBDemodGUI::downloadFinished - aircraftDatabase.csv not in expected dir. Extracting all."; + if (!reader.extractAll(getDataDir())) { + qWarning() << "ADSBDemodGUI::downloadFinished - Failed to extract files from " << filename; + } + } + readOSNDB(getOSNDBFilename()); // Convert to condensed format for faster loading later m_progressDialog->setLabelText("Processing."); AircraftInformation::writeFastDB(getFastDBFilename(), m_aircraftInfo); @@ -2121,6 +2911,341 @@ void ADSBDemodGUI::on_device_currentIndexChanged(int index) } } +QString ADSBDemodGUI::get3DModel(const QString &aircraftType, const QString &operatorICAO) const +{ + QString aircraftTypeOperator = aircraftType + "_" + operatorICAO; + if (m_3DModels.contains(aircraftTypeOperator)) { + return m_3DModels.value(aircraftTypeOperator); + } + if (m_settings.m_verboseModelMatching) { + qDebug() << "ADS-B: No livery for " << aircraftTypeOperator; + } + return ""; +} + +QString ADSBDemodGUI::get3DModel(const QString &aircraftType) const +{ + if (m_3DModels.contains(aircraftType)) { + return m_3DModels.value(aircraftType); + } + if (m_settings.m_verboseModelMatching) { + qDebug() << "ADS-B: No aircraft for " << aircraftType; + } + return ""; +} + +void ADSBDemodGUI::get3DModel(Aircraft *aircraft) +{ + QString model; + if (aircraft->m_aircraftInfo && !aircraft->m_aircraftInfo->m_model.isEmpty()) + { + QString aircraftType; + for (auto mm : m_3DModelMatch) + { + if (mm->match(aircraft->m_aircraftInfo->m_model, aircraft->m_aircraftInfo->m_manufacturerName, aircraftType)) + { + // Look for operator specific livery + if (!aircraft->m_aircraftInfo->m_operatorICAO.isEmpty()) { + model = get3DModel(aircraftType, aircraft->m_aircraftInfo->m_operatorICAO); + } + if (model.isEmpty()) { + // Try for aircraft with out specific livery + model = get3DModel(aircraftType); + } + if (!model.isEmpty()) + { + aircraft->m_aircraft3DModel = model; + if (m_modelAltitudeOffset.contains(aircraftType)) + { + aircraft->m_modelAltitudeOffset = m_modelAltitudeOffset.value(aircraftType); + aircraft->m_labelAltitudeOffset = m_labelAltitudeOffset.value(aircraftType); + } + } + break; + } + } + if (m_settings.m_verboseModelMatching) + { + if (model.isEmpty()) { + qDebug() << "ADS-B: No 3D model for " << aircraft->m_aircraftInfo->m_model << " " << aircraft->m_aircraftInfo->m_operatorICAO << " for " << aircraft->m_icaoHex; + } else { + qDebug() << "ADS-B: Matched " << aircraft->m_aircraftInfo->m_model << " " << aircraft->m_aircraftInfo->m_operatorICAO << " to " << model << " for " << aircraft->m_icaoHex; + } + } + } +} + +void ADSBDemodGUI::update3DModels() +{ + // Look for all aircraft gltfs in 3d directory + QString modelDir = getDataDir() + "/3d"; + QStringList subDirs = {"BB_Airbus_png", "BB_Boeing_png", "BB_Jets_png", "BB_Props_png", "BB_GA_png", "BB_Mil_png", "BB_Heli_png"}; + + for (auto subDir : subDirs) + { + QString dirName = modelDir + "/" + subDir; + QDir dir(dirName); + QStringList aircrafts = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + for (auto aircraft : aircrafts) + { + if (m_settings.m_verboseModelMatching) { + qDebug() << "Aircraft " << aircraft; + } + QDir aircraftDir(dir.filePath(aircraft)); + QStringList gltfs = aircraftDir.entryList({"*.gltf"}); + for (auto gltf : gltfs) + { + QStringList filenameParts = gltf.split(".")[0].split("_"); + if (filenameParts.size() == 2) + { + QString livery = filenameParts[1]; + if (m_settings.m_verboseModelMatching) { + qDebug() << "Aircraft " << aircraft << "Livery " << livery; + } + // Only use relative path, as Map feature will add the prefix + m_3DModels.insert(aircraft + "_" + livery, subDir + "/" + aircraft + "/" + gltf); + } + } + // Also add an entry just using aircraft type, for when we can't find a operator specific livery + // Just use first from the list for now + if (gltfs.size() > 0) { + m_3DModels.insert(aircraft, subDir + "/" + aircraft + "/" + gltfs[0]); + } + } + } + + // Vertical offset so undercarriage isn't underground, because 0,0,0 is in the middle of the model + // rather than at the bottom + m_modelAltitudeOffset.insert("A306", 4.6f); + m_modelAltitudeOffset.insert("A310", 4.6f); + m_modelAltitudeOffset.insert("A318", 3.7f); + m_modelAltitudeOffset.insert("A319", 3.5f); + m_modelAltitudeOffset.insert("A320", 3.5f); + m_modelAltitudeOffset.insert("A321", 3.5f); + m_modelAltitudeOffset.insert("A332", 5.52f); + m_modelAltitudeOffset.insert("A333", 5.52f); + m_modelAltitudeOffset.insert("A334", 5.52f); + m_modelAltitudeOffset.insert("A343", 4.65f); + m_modelAltitudeOffset.insert("A345", 4.65f); + m_modelAltitudeOffset.insert("A346", 4.65f); + m_modelAltitudeOffset.insert("A388", 5.75f); + m_modelAltitudeOffset.insert("B717", 0.0f); + m_modelAltitudeOffset.insert("B733", 3.1f); + m_modelAltitudeOffset.insert("B734", 3.27f); + m_modelAltitudeOffset.insert("B737", 3.0f); + m_modelAltitudeOffset.insert("B738", 3.31f); + m_modelAltitudeOffset.insert("B739", 3.32f); + m_modelAltitudeOffset.insert("B74F", 5.3f); + m_modelAltitudeOffset.insert("B744", 5.25f); + m_modelAltitudeOffset.insert("B752", 3.6f); + m_modelAltitudeOffset.insert("B763", 4.44f); + m_modelAltitudeOffset.insert("B772", 5.57f); + m_modelAltitudeOffset.insert("B773", 5.6f); + m_modelAltitudeOffset.insert("B77L", 5.57f); + m_modelAltitudeOffset.insert("B77W", 5.57f); + m_modelAltitudeOffset.insert("B788", 4.1f); + m_modelAltitudeOffset.insert("BE20", 1.48f); + m_modelAltitudeOffset.insert("C150", 1.05f); + m_modelAltitudeOffset.insert("C172", 1.16f); + m_modelAltitudeOffset.insert("C421", 1.16f); + m_modelAltitudeOffset.insert("H25B", 1.45f); + m_modelAltitudeOffset.insert("LJ45", 1.27f); + m_modelAltitudeOffset.insert("B462", 1.8f); + m_modelAltitudeOffset.insert("B463", 1.9f); + m_modelAltitudeOffset.insert("CRJ2", 1.3f); + m_modelAltitudeOffset.insert("CRJ7", 1.66f); + m_modelAltitudeOffset.insert("CRJ9", 2.27f); + m_modelAltitudeOffset.insert("CRJX", 2.49f); + m_modelAltitudeOffset.insert("DC10", 5.2f); + m_modelAltitudeOffset.insert("E135", 1.88f); + m_modelAltitudeOffset.insert("E145", 1.86f); + m_modelAltitudeOffset.insert("E170", 2.3f); + m_modelAltitudeOffset.insert("E190", 3.05f); + m_modelAltitudeOffset.insert("E195", 2.97f); + m_modelAltitudeOffset.insert("F28", 2.34f); + m_modelAltitudeOffset.insert("F70", 2.43f); + m_modelAltitudeOffset.insert("F100", 2.23f); + m_modelAltitudeOffset.insert("J328", 1.01f); + m_modelAltitudeOffset.insert("MD11", 5.22f); + m_modelAltitudeOffset.insert("MD83", 2.71f); + m_modelAltitudeOffset.insert("MD90", 2.62f); + m_modelAltitudeOffset.insert("AT42", 1.75f); + m_modelAltitudeOffset.insert("AT72", 1.83f); + m_modelAltitudeOffset.insert("D328", 0.99f); + m_modelAltitudeOffset.insert("DH8D", 1.65f); + m_modelAltitudeOffset.insert("F50", 2.16f); + m_modelAltitudeOffset.insert("JS41", 1.9f); + m_modelAltitudeOffset.insert("L410", 1.1f); + m_modelAltitudeOffset.insert("SB20", 2.0f); + m_modelAltitudeOffset.insert("SF34", 1.89f); + + // Label offsets (from bottom of aircraft) + m_labelAltitudeOffset.insert("A306", 10.0f); + m_labelAltitudeOffset.insert("A310", 15.0f); + m_labelAltitudeOffset.insert("A318", 10.0f); + m_labelAltitudeOffset.insert("A319", 10.0f); + m_labelAltitudeOffset.insert("A320", 10.0f); + m_labelAltitudeOffset.insert("A321", 10.0f); + m_labelAltitudeOffset.insert("A332", 14.0f); + m_labelAltitudeOffset.insert("A333", 14.0f); + m_labelAltitudeOffset.insert("A334", 14.0f); + m_labelAltitudeOffset.insert("A343", 14.0f); + m_labelAltitudeOffset.insert("A345", 14.0f); + m_labelAltitudeOffset.insert("A346", 14.0f); + m_labelAltitudeOffset.insert("A388", 20.0f); + m_labelAltitudeOffset.insert("B717", 7.5f); + m_labelAltitudeOffset.insert("B733", 10.0f); + m_labelAltitudeOffset.insert("B734", 10.0f); + m_labelAltitudeOffset.insert("B737", 10.0f); + m_labelAltitudeOffset.insert("B738", 10.0f); + m_labelAltitudeOffset.insert("B739", 10.0f); + m_labelAltitudeOffset.insert("B74F", 15.0f); + m_labelAltitudeOffset.insert("B744", 15.0f); + m_labelAltitudeOffset.insert("B752", 12.0f); + m_labelAltitudeOffset.insert("B763", 14.0f); + m_labelAltitudeOffset.insert("B772", 14.0f); + m_labelAltitudeOffset.insert("B773", 14.0f); + m_labelAltitudeOffset.insert("B77L", 14.0f); + m_labelAltitudeOffset.insert("B77W", 14.0f); + m_labelAltitudeOffset.insert("B788", 14.0f); + m_labelAltitudeOffset.insert("BE20", 4.0f); + m_labelAltitudeOffset.insert("C150", 3.0f); + m_labelAltitudeOffset.insert("C172", 3.0f); + m_labelAltitudeOffset.insert("C421", 4.0f); + m_labelAltitudeOffset.insert("H25B", 5.0f); + m_labelAltitudeOffset.insert("LJ45", 5.0f); + m_labelAltitudeOffset.insert("B462", 7.0f); + m_labelAltitudeOffset.insert("B463", 7.0f); + m_labelAltitudeOffset.insert("CRJ2", 5.5f); + m_labelAltitudeOffset.insert("CRJ7", 6.0f); + m_labelAltitudeOffset.insert("CRJ9", 6.0f); + m_labelAltitudeOffset.insert("CRJX", 6.0f); + m_labelAltitudeOffset.insert("DC10", 15.0f); + m_labelAltitudeOffset.insert("E135", 5.0f); + m_labelAltitudeOffset.insert("E145", 5.0f); + m_labelAltitudeOffset.insert("E170", 8.0f); + m_labelAltitudeOffset.insert("E190", 8.5f); + m_labelAltitudeOffset.insert("E195", 8.5f); + m_labelAltitudeOffset.insert("F28", 7.0f); + m_labelAltitudeOffset.insert("F70", 6.5f); + m_labelAltitudeOffset.insert("F100", 6.5f); + m_labelAltitudeOffset.insert("J328", 5.0f); // Check + m_labelAltitudeOffset.insert("MD11", 15.0f); + m_labelAltitudeOffset.insert("MD83", 7.5f); + m_labelAltitudeOffset.insert("MD90", 7.5f); + m_labelAltitudeOffset.insert("AT42", 7.0f); + m_labelAltitudeOffset.insert("AT72", 7.0f); + m_labelAltitudeOffset.insert("D328", 6.0f); + m_labelAltitudeOffset.insert("DH8D", 6.5f); + m_labelAltitudeOffset.insert("F50", 7.0f); + m_labelAltitudeOffset.insert("JS41", 5.0f); + m_labelAltitudeOffset.insert("L410", 5.0f); + m_labelAltitudeOffset.insert("SB20", 6.5f); + m_labelAltitudeOffset.insert("SF34", 6.0f); + + // Map from database names to 3D model names + m_3DModelMatch.append(new ModelMatch("A300.*", "A306")); // A300 B4 is A300-600, but use for others as closest match + m_3DModelMatch.append(new ModelMatch("A310.*", "A310")); + m_3DModelMatch.append(new ModelMatch("A318.*", "A318")); + m_3DModelMatch.append(new ModelMatch("A.?319.*", "A319")); + m_3DModelMatch.append(new ModelMatch("A.?320.*", "A320")); + m_3DModelMatch.append(new ModelMatch("A.?321.*", "A321")); + m_3DModelMatch.append(new ModelMatch("A330.2.*", "A332")); + m_3DModelMatch.append(new ModelMatch("A330.3.*", "A333")); + m_3DModelMatch.append(new ModelMatch("A330.4.*", "A342")); + m_3DModelMatch.append(new ModelMatch("A340.3.*", "A343")); + m_3DModelMatch.append(new ModelMatch("A340.5.*", "A345")); + m_3DModelMatch.append(new ModelMatch("A340.6.*", "A346")); + m_3DModelMatch.append(new ModelMatch("A350.*", "A333")); // No A350 model - use 330 as twin engine + m_3DModelMatch.append(new ModelMatch("A380.*", "A388")); + + m_3DModelMatch.append(new ModelMatch("737.2.*", "B733")); // No 200 model + m_3DModelMatch.append(new ModelMatch("737.3.*", "B733")); + m_3DModelMatch.append(new ModelMatch("737.4.*", "B734")); + m_3DModelMatch.append(new ModelMatch("737.5.*", "B734")); // No 500 model + m_3DModelMatch.append(new ModelMatch("737.6.*", "B737")); // No 600 model + m_3DModelMatch.append(new ModelMatch("737NG.6.*", "B737")); + m_3DModelMatch.append(new ModelMatch("737.7.*", "B737")); + m_3DModelMatch.append(new ModelMatch("737NG.7.*", "B737")); + m_3DModelMatch.append(new ModelMatch("737.8.*", "B738")); + m_3DModelMatch.append(new ModelMatch("737NG.8.*", "B738")); // No Max model yet + m_3DModelMatch.append(new ModelMatch("737MAX.8.*", "B738")); + m_3DModelMatch.append(new ModelMatch("737.9", "B739")); + m_3DModelMatch.append(new ModelMatch("737NG.9", "B739")); + m_3DModelMatch.append(new ModelMatch("737MAX.9", "B739")); + m_3DModelMatch.append(new ModelMatch("B747.*F", "B74F")); + m_3DModelMatch.append(new ModelMatch("B747.*\\(F\\)", "B74F")); + m_3DModelMatch.append(new ModelMatch("747.*", "B744")); + m_3DModelMatch.append(new ModelMatch("757.*", "B752")); + m_3DModelMatch.append(new ModelMatch("767.*", "B763")); + m_3DModelMatch.append(new ModelMatch("777.2.*LR.*", "B77L")); + m_3DModelMatch.append(new ModelMatch("777.2.*", "B772")); + m_3DModelMatch.append(new ModelMatch("777.3.*ER.*", "B77W")); + m_3DModelMatch.append(new ModelMatch("777.3.*", "B773")); + m_3DModelMatch.append(new ModelMatch("777.*", "B772")); + m_3DModelMatch.append(new ModelMatch("787.*", "B788")); + m_3DModelMatch.append(new ModelMatch("717.*", "B717")); + // No 727 model + + // Jets + m_3DModelMatch.append(new ModelMatch(".*EMB.135.*", "E135")); + m_3DModelMatch.append(new ModelMatch(".*ERJ.135.*", "E135")); + m_3DModelMatch.append(new ModelMatch("Embraer 135.*", "E135")); + m_3DModelMatch.append(new ModelMatch(".*EMB.145.*", "E145")); + m_3DModelMatch.append(new ModelMatch(".*ERJ.145.*", "E145")); + m_3DModelMatch.append(new ModelMatch("Embraer 145.*", "E145")); + m_3DModelMatch.append(new ModelMatch(".*EMB.170.*", "E170")); + m_3DModelMatch.append(new ModelMatch(".*ERJ.170.*", "E170")); + m_3DModelMatch.append(new ModelMatch("Embraer 170.*", "E170")); + m_3DModelMatch.append(new ModelMatch(".*EMB.190.*", "E190")); + m_3DModelMatch.append(new ModelMatch(".*ERJ.190.*", "E190")); + m_3DModelMatch.append(new ModelMatch("Embraer 190.*", "E190")); + m_3DModelMatch.append(new ModelMatch(".*EMB.195.*", "E195")); + m_3DModelMatch.append(new ModelMatch(".*ERJ.195.*", "E195")); + m_3DModelMatch.append(new ModelMatch("Embraer 195.*", "E195")); + + m_3DModelMatch.append(new ModelMatch(".*CRJ.200.*", "CRJ2")); + m_3DModelMatch.append(new ModelMatch(".*CRJ.700.*", "CRJ7")); + m_3DModelMatch.append(new ModelMatch(".*CRJ.900.*", "CRJ9")); + m_3DModelMatch.append(new ModelMatch(".*CRJ.1000.*", "CRJX")); + + // PNGs missing + //m_3DModelMatch.append(new ModelMatch("(BAE )?146.2.*", "B462")); + //m_3DModelMatch.append(new ModelMatch("(BAE )?146.3.*", "B463")); + + m_3DModelMatch.append(new ModelMatch("DC-10.*", "DC10")); + + m_3DModelMatch.append(new ModelMatch(".*MD.11.*", "MD11")); + m_3DModelMatch.append(new ModelMatch(".*MD.83.*", "MD83")); + m_3DModelMatch.append(new ModelMatch(".*MD.90.*", "MD90")); + + m_3DModelMatch.append(new ModelMatch(".*F28.*", "F28")); + m_3DModelMatch.append(new ModelMatch(".*F70.*", "F70")); + m_3DModelMatch.append(new ModelMatch(".*F100.*", "F100")); + + // GA + m_3DModelMatch.append(new ModelMatch(".*B200.*", "BE20")); + m_3DModelMatch.append(new ManufacturerModelMatch(".*200.*", ".*Beech.*", "BE20")); + m_3DModelMatch.append(new ModelMatch(".*150.*", "C150")); + m_3DModelMatch.append(new ModelMatch(".*172.*", "C172")); + m_3DModelMatch.append(new ModelMatch(".*421.*", "C421")); + m_3DModelMatch.append(new ModelMatch(".*125.*", "H25B")); + m_3DModelMatch.append(new ManufacturerModelMatch(".*400.*", "Hawker.*", "H25B")); + m_3DModelMatch.append(new ManufacturerModelMatch(".*400.*", "Raytheon.*", "H25B")); + m_3DModelMatch.append(new ModelMatch(".*Learjet.*", "LJ45")); + + // Props + m_3DModelMatch.append(new ModelMatch("ATR.*42.*", "AT42")); + m_3DModelMatch.append(new ModelMatch("ATR.*72.*", "AT72")); + m_3DModelMatch.append(new ModelMatch("Do 328.*", "D328")); + m_3DModelMatch.append(new ModelMatch("DHC-8.*", "DH8D")); + m_3DModelMatch.append(new ModelMatch(".*F50.*", "F50")); + m_3DModelMatch.append(new ModelMatch("Jetstream 41.*", "JS41")); + m_3DModelMatch.append(new ModelMatch(".*L.410.*", "L410")); + m_3DModelMatch.append(new ModelMatch("SAAB.2000.*", "SB20")); + m_3DModelMatch.append(new ManufacturerModelMatch(".*340.*", "Saab.*", "SF34")); +} + void ADSBDemodGUI::updateAirports() { m_airportModel.removeAllAirports(); @@ -2341,7 +3466,7 @@ void ADSBDemodGUI::highlightAircraft(Aircraft *aircraft) { // Download photo updatePhotoText(aircraft); - m_planeSpotters.getAircraftPhoto(QString::number(aircraft->m_icao, 16)); + m_planeSpotters.getAircraftPhoto(aircraft->m_icaoHex); } } } @@ -2373,32 +3498,11 @@ void ADSBDemodGUI::feedSelect() // Show display settings dialog void ADSBDemodGUI::on_displaySettings_clicked() { - ADSBDemodDisplayDialog dialog(m_settings.m_removeTimeout, m_settings.m_airportRange, m_settings.m_airportMinimumSize, - m_settings.m_displayHeliports, m_settings.m_siUnits, - m_settings.m_tableFontName, m_settings.m_tableFontSize, - m_settings.m_displayDemodStats, m_settings.m_autoResizeTableColumns, - m_settings.m_apiKey, m_settings.m_airspaces, m_settings.m_airspaceRange, - m_settings.m_mapType, m_settings.m_displayNavAids, m_settings.m_displayPhotos); + bool oldSiUnits = m_settings.m_siUnits; + ADSBDemodDisplayDialog dialog(&m_settings); if (dialog.exec() == QDialog::Accepted) { - bool unitsChanged = m_settings.m_siUnits != dialog.m_siUnits; - - m_settings.m_removeTimeout = dialog.m_removeTimeout; - m_settings.m_airportRange = dialog.m_airportRange; - m_settings.m_airportMinimumSize = dialog.m_airportMinimumSize; - m_settings.m_displayHeliports = dialog.m_displayHeliports; - m_settings.m_siUnits = dialog.m_siUnits; - m_settings.m_tableFontName = dialog.m_fontName; - m_settings.m_tableFontSize = dialog.m_fontSize; - m_settings.m_displayDemodStats = dialog.m_displayDemodStats; - m_settings.m_autoResizeTableColumns = dialog.m_autoResizeTableColumns; - m_settings.m_apiKey = dialog.m_apiKey; - m_settings.m_airspaces = dialog.m_airspaces; - m_settings.m_airspaceRange = dialog.m_airspaceRange; - m_settings.m_mapType = dialog.m_mapType; - m_settings.m_displayNavAids = dialog.m_displayNavAids; - m_settings.m_displayPhotos = dialog.m_displayPhotos; - + bool unitsChanged = m_settings.m_siUnits != oldSiUnits; if (unitsChanged) { m_aircraftModel.allAircraftUpdated(); } @@ -2602,6 +3706,9 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb // Get signals when columns change connect(ui->adsbData->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), SLOT(adsbData_sectionMoved(int, int, int))); connect(ui->adsbData->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(adsbData_sectionResized(int, int, int))); + // Context menu + ui->adsbData->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->adsbData, SIGNAL(customContextMenuRequested(QPoint)), SLOT(adsbData_customContextMenuRequested(QPoint))); ui->photoHeader->setVisible(false); ui->photoFlag->setVisible(false); @@ -2640,12 +3747,18 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb Real stationAltitude = MainCore::instance()->getSettings().getAltitude(); m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); + // These are the default values in sdrbase/settings/preferences.cpp + if ((stationLatitude == 49.012423) && (stationLongitude == 8.418125)) { + ui->warning->setText("Please set your antenna location under Preferences > My Position"); + } + // Add airports within range of My Position if (m_airportInfo != nullptr) { updateAirports(); } updateAirspaces(); updateNavAids(); + update3DModels(); // Initialise text to speech engine m_speech = new QTextToSpeech(this); @@ -2658,6 +3771,8 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb updateDeviceSetList(); displaySettings(); applySettings(true); + + ui->map->installEventFilter(this); } ADSBDemodGUI::~ADSBDemodGUI() @@ -2689,6 +3804,7 @@ ADSBDemodGUI::~ADSBDemodGUI() } qDeleteAll(m_airspaces); qDeleteAll(m_navAids); + qDeleteAll(m_3DModelMatch); } void ADSBDemodGUI::applySettings(bool force) @@ -3112,9 +4228,10 @@ void ADSBDemodGUI::on_logOpen_clicked() QDateTime dateTime = QDateTime::currentDateTime(); // So they aren't removed immediately as too old QByteArray bytes = QByteArray::fromHex(cols[dataCol].toLatin1()); float correlation = cols[correlationCol].toFloat(); - handleADSB(bytes, dateTime, correlation, correlation); - if (count % 1000 == 0) + handleADSB(bytes, dateTime, correlation, correlation, false); + if ((count > 0) && (count % 100000 == 0)) { + dialog.setText(QString("Reading ADS-B data\n%1").arg(count)); QApplication::processEvents(); if (dialog.clickedButton()) { cancelled = true; @@ -3123,6 +4240,7 @@ void ADSBDemodGUI::on_logOpen_clicked() count++; } } + m_aircraftModel.allAircraftUpdated(); dialog.close(); } else @@ -3182,3 +4300,60 @@ void ADSBDemodGUI::downloadNavAidsFinished() m_progressDialog = nullptr; } } + +int ADSBDemodGUI::grayToBinary(int gray, int bits) const +{ + int binary = 0; + for (int i = bits - 1; i >= 0; i--) { + binary = binary | ((((1 << (i+1)) & binary) >> 1) ^ ((1 << i) & gray)); + } + return binary; +} + +void ADSBDemodGUI::redrawMap() +{ + // An awful workaround for https://bugreports.qt.io/browse/QTBUG-100333 + // Also used in Map feature + QQuickItem *item = ui->map->rootObject(); + if (item) + { + QObject *object = item->findChild("map"); + if (object) + { + double zoom = object->property("zoomLevel").value(); + object->setProperty("zoomLevel", QVariant::fromValue(zoom+1)); + object->setProperty("zoomLevel", QVariant::fromValue(zoom)); + } + } +} + +void ADSBDemodGUI::showEvent(QShowEvent *event) +{ + if (!event->spontaneous()) + { + // Workaround for https://bugreports.qt.io/browse/QTBUG-100333 + // MapQuickItems can be in wrong position when window is first displayed + QTimer::singleShot(500, [this] { + redrawMap(); + }); + } +} + +bool ADSBDemodGUI::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == ui->map) + { + if (event->type() == QEvent::Resize) + { + // Workaround for https://bugreports.qt.io/browse/QTBUG-100333 + // MapQuickItems can be in wrong position after vertical resize + QResizeEvent *resizeEvent = static_cast(event); + QSize oldSize = resizeEvent->oldSize(); + QSize size = resizeEvent->size(); + if (oldSize.height() != size.height()) { + redrawMap(); + } + } + } + return false; +} diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.h b/plugins/channelrx/demodadsb/adsbdemodgui.h index 14c033f62..56b278a8b 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.h +++ b/plugins/channelrx/demodadsb/adsbdemodgui.h @@ -41,6 +41,8 @@ #include "settings/rollupstate.h" #include "maincore.h" +#include "SWGMapItem.h" + #include "adsbdemodsettings.h" #include "ourairportsdb.h" #include "osndb.h" @@ -83,11 +85,14 @@ public: // Data about an aircraft extracted from an ADS-B frames struct Aircraft { int m_icao; // 24-bit ICAO aircraft address + QString m_icaoHex; QString m_callsign; // Flight callsign QString m_flight; // Guess at flight number Real m_latitude; // Latitude in decimal degrees Real m_longitude; // Longitude in decimal degrees int m_altitude; // Altitude in feet + bool m_onSurface; // Indicates if on surface or airbourne + bool m_altitudeGNSS; // Altitude is GNSS HAE (Height above WGS-84 ellipsoid) rather than barometric alitute (relative to 29.92 Hg) int m_speed; // Speed in knots enum SpeedType { GS, // Ground speed @@ -95,14 +100,14 @@ struct Aircraft { IAS // Indicated air speed } m_speedType; static const char *m_speedTypeNames[]; - int m_heading; // Heading in degrees + float m_heading; // Heading in degrees int m_verticalRate; // Vertical climb rate in ft/min QString m_emitterCategory; // Aircraft type QString m_status; // Aircraft status int m_squawk; // Mode-A code Real m_range; // Distance from station to aircraft Real m_azimuth; // Azimuth from station to aircraft - Real m_elevation; // Elevation from station to aicraft; + Real m_elevation; // Elevation from station to aicraft QDateTime m_time; // When last updated bool m_positionValid; // Indicates if we have valid data for the above fields @@ -130,7 +135,28 @@ struct Aircraft { QVariantList m_coordinates; // Coordinates we've recorded the aircraft at AircraftInformation *m_aircraftInfo; // Info about the aircraft from the database + QString m_aircraft3DModel; // 3D model for map based on aircraft type + QString m_aircraftCat3DModel; // 3D model based on aircraft category + float m_modelAltitudeOffset; // Altitude adjustment so aircraft model doesn't go underground + float m_labelAltitudeOffset; // How height to position label above aircraft ADSBDemodGUI *m_gui; + QString m_flagIconURL; + QString m_airlineIconURL; + + // For animation on 3D map + float m_runwayAltitude; + bool m_runwayAltitudeValid; + bool m_gearDown; + float m_flaps; // 0 - no flaps, 1 - full flaps + bool m_rotorStarted; // Rotors started on 'Rotorcraft' + bool m_engineStarted; // Engines started (typically propellors) + QDateTime m_positionDateTime; + QDateTime m_orientationDateTime; + QDateTime m_headingDateTime; + QDateTime m_prevHeadingDateTime; + int m_prevHeading; + float m_pitch; // Estimated pitch based on vertical rate + float m_roll; // Estimated roll based on rate of change in heading bool m_notified; // Set when a notification has been made for this aircraft, so we don't repeat it @@ -175,7 +201,10 @@ struct Aircraft { m_latitude(0), m_longitude(0), m_altitude(0), + m_onSurface(false), + m_altitudeGNSS(false), m_speed(0), + m_speedType(GS), m_heading(0), m_verticalRate(0), m_azimuth(0), @@ -193,7 +222,17 @@ struct Aircraft { m_isHighlighted(false), m_showAll(false), m_aircraftInfo(nullptr), + m_modelAltitudeOffset(0.0f), + m_labelAltitudeOffset(5.0f), m_gui(gui), + m_runwayAltitude(0.0), + m_runwayAltitudeValid(false), + m_gearDown(false), + m_flaps(0.0), + m_rotorStarted(false), + m_engineStarted(false), + m_pitch(0.0), + m_roll(0.0), m_notified(false) { for (int i = 0; i < 2; i++) @@ -237,8 +276,8 @@ struct Aircraft { m_ataItem = new QTableWidgetItem(); } - QString getImage(); - QString getText(bool all=false); + QString getImage() const; + QString getText(bool all=false) const; // Name to use when selected as a target QString targetName() @@ -348,6 +387,8 @@ public: allAircraftUpdated(); } + Q_INVOKABLE void findOnMap(int index); + private: QList m_aircrafts; bool m_flightPaths; @@ -637,6 +678,65 @@ private: QList m_selected; }; +// Match 3D models to Opensky-Network Aircraft database +// The database doesn't use consistent names for aircraft, so we use regexps +class ModelMatch { +public: + ModelMatch(const QString &aircraftRegExp, const QString &model) : + m_aircraftRegExp(aircraftRegExp), + m_model(model) + { + m_aircraftRegExp.optimize(); + } + + virtual bool match(const QString &aircraft, const QString &manufacturer, QString &model) + { + QRegularExpressionMatch match = m_aircraftRegExp.match(aircraft); + if (match.hasMatch()) + { + model = m_model; + return true; + } + else + { + return false; + } + } + +protected: + QRegularExpression m_aircraftRegExp; + QString m_model; +}; + +// For very generic aircraft names, also match against manufacturer name +class ManufacturerModelMatch : public ModelMatch { +public: + ManufacturerModelMatch(const QString &modelRegExp, const QString &manufacturerRegExp, const QString &model) : + ModelMatch(modelRegExp, model), + m_manufacturerRegExp(manufacturerRegExp) + { + m_manufacturerRegExp.optimize(); + } + + virtual bool match(const QString &aircraft, const QString &manufacturer, QString &model) override + { + QRegularExpressionMatch matchManufacturer = m_manufacturerRegExp.match(manufacturer); + if (matchManufacturer.hasMatch()) + { + QRegularExpressionMatch matchAircraft = m_aircraftRegExp.match(aircraft); + if (matchAircraft.hasMatch()) + { + model = m_model; + return true; + } + } + return false; + } + +protected: + QRegularExpression m_manufacturerRegExp; +}; + class ADSBDemodGUI : public ChannelGUI { Q_OBJECT @@ -652,8 +752,11 @@ public: void targetAircraft(Aircraft *aircraft); void target(const QString& name, float az, float el, float range); bool setFrequency(float frequency); - bool useSIUints() { return m_settings.m_siUnits; } + bool useSIUints() const { return m_settings.m_siUnits; } Q_INVOKABLE void clearHighlighted(); + QString get3DModel(const QString &aircraft, const QString &operatorICAO) const; + QString get3DModel(const QString &aircraft) const; + void get3DModel(Aircraft *aircraft); public slots: void channelMarkerChangedByCursor(); @@ -683,6 +786,7 @@ private: AirspaceModel m_airspaceModel; NavAidModel m_navAidModel; QHash m_airlineIcons; // Hashed on airline ICAO + QHash m_airlineMissingIcons; // Hash containing which ICAOs we don't have icons for QHash m_flagIcons; // Hashed on country QHash *m_prefixMap; // Registration to country (flag name) QHash *m_militaryMap; // Operator airforce to military (flag name) @@ -710,6 +814,10 @@ private: quint16 m_osmPort; OpenAIP m_openAIP; ADSBOSMTemplateServer *m_templateServer; + QHash m_3DModels; // Hashed aircraft_icao or just aircraft + QList m_3DModelMatch; // Map of database aircraft names to 3D model names + QHash m_modelAltitudeOffset; + QHash m_labelAltitudeOffset; explicit ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0); virtual ~ADSBDemodGUI(); @@ -721,11 +829,19 @@ private: bool handleMessage(const Message& message); void updatePosition(Aircraft *aircraft); bool updateLocalPosition(Aircraft *aircraft, double latitude, double longitude, bool surfacePosition); + void sendToMap(Aircraft *aircraft, QList *animations); void handleADSB( const QByteArray data, const QDateTime dateTime, float correlation, - float correlationOnes); + float correlationOnes, + bool updateModel); + QList *animate(QDateTime dateTime, Aircraft *aircraft, bool prevAltitudeValid, int prevAltitude); + SWGSDRangel::SWGMapAnimation *gearAnimation(QDateTime startDateTime, bool up); + SWGSDRangel::SWGMapAnimation *flapsAnimation(QDateTime startDateTime, float currentFlaps, float flaps); + SWGSDRangel::SWGMapAnimation *slatsAnimation(QDateTime startDateTime, bool retract); + SWGSDRangel::SWGMapAnimation *rotorAnimation(QDateTime startDateTime, bool stop); + SWGSDRangel::SWGMapAnimation *engineAnimation(QDateTime startDateTime, int engine, bool stop); void checkStaticNotification(Aircraft *aircraft); void checkDynamicNotification(Aircraft *aircraft); void speechNotification(Aircraft *aircraft, const QString &speech); @@ -735,6 +851,7 @@ private: QString getDataDir(); QString getAirportDBFilename(); QString getAirportFrequenciesDBFilename(); + QString getOSNDBZipFilename(); QString getOSNDBFilename(); QString getFastDBFilename(); qint64 fileAgeInDays(QString filename); @@ -743,10 +860,13 @@ private: void readAirportFrequenciesDB(const QString& filename); bool readOSNDB(const QString& filename); bool readFastDB(const QString& filename); + void update3DModels(); void updateAirports(); void updateAirspaces(); void updateNavAids(); + QString getAirlineIconPath(const QString &operatorICAO); QIcon *getAirlineIcon(const QString &operatorICAO); + QString getFlagIconPath(const QString &country); QIcon *getFlagIcon(const QString &country); void updateDeviceSetList(); QAction *createCheckableItem(QString& text, int idx, bool checked); @@ -756,6 +876,9 @@ private: void applyMapSettings(); void updatePhotoText(Aircraft *aircraft); void updatePhotoFlightInformation(Aircraft *aircraft); + void findOnChannelMap(Aircraft *aircraft); + int grayToBinary(int gray, int bits) const; + void redrawMap(); void leaveEvent(QEvent*); void enterEvent(QEvent*); @@ -766,6 +889,7 @@ private slots: void on_threshold_valueChanged(int value); void on_phaseSteps_valueChanged(int value); void on_tapsPerPhase_valueChanged(int value); + void adsbData_customContextMenuRequested(QPoint point); void on_adsbData_cellClicked(int row, int column); void on_adsbData_cellDoubleClicked(int row, int column); void adsbData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex); @@ -778,6 +902,7 @@ private slots: void on_feed_clicked(bool checked); void on_notifications_clicked(); void on_flightInfo_clicked(); + void on_findOnMapFeature_clicked(); void on_getOSNDB_clicked(); void on_getAirportDB_clicked(); void on_getAirspacesDB_clicked(); @@ -801,6 +926,8 @@ private slots: void downloadAirspaceFinished(); void downloadNavAidsFinished(); void photoClicked(); + virtual void showEvent(QShowEvent *event); + virtual bool eventFilter(QObject *obj, QEvent *event); signals: void homePositionChanged(); diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.ui b/plugins/channelrx/demodadsb/adsbdemodgui.ui index 2df681c6c..f74220be9 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.ui +++ b/plugins/channelrx/demodadsb/adsbdemodgui.ui @@ -24,7 +24,6 @@ - Liberation Sans 9 @@ -101,7 +100,6 @@ - Liberation Mono 12 @@ -190,7 +188,6 @@ - Liberation Mono 8 @@ -691,6 +688,23 @@
+ + + + Find selected aircraft on feature map + + + ... + + + + :/gridpolar.png:/gridpolar.png + + + false + + + diff --git a/plugins/channelrx/demodadsb/adsbdemodreport.h b/plugins/channelrx/demodadsb/adsbdemodreport.h index 9c4223480..699ab405d 100644 --- a/plugins/channelrx/demodadsb/adsbdemodreport.h +++ b/plugins/channelrx/demodadsb/adsbdemodreport.h @@ -43,10 +43,11 @@ public: static MsgReportADSB* create( QByteArray data, float preambleCorrelation, - float correlationOnes + float correlationOnes, + QDateTime dateTime ) { - return new MsgReportADSB(data, preambleCorrelation, correlationOnes); + return new MsgReportADSB(data, preambleCorrelation, correlationOnes, dateTime); } private: @@ -58,14 +59,15 @@ public: MsgReportADSB( QByteArray data, float preambleCorrelation, - float correlationOnes + float correlationOnes, + QDateTime dateTime ) : Message(), m_data(data), m_preambleCorrelation(preambleCorrelation), - m_correlationOnes(correlationOnes) + m_correlationOnes(correlationOnes), + m_dateTime(dateTime) { - m_dateTime = QDateTime::currentDateTime(); } }; diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp index 68a1294d4..375d2cda1 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp @@ -81,6 +81,8 @@ void ADSBDemodSettings::resetToDefaults() m_mapType = AVIATION_LIGHT; m_displayNavAids = true; m_displayPhotos = true; + m_verboseModelMatching = false; + m_airfieldElevation = 0; } QByteArray ADSBDemodSettings::serialize() const @@ -141,6 +143,9 @@ QByteArray ADSBDemodSettings::serialize() const s.writeBlob(43, m_rollupState->serialize()); } + s.writeBool(44, m_verboseModelMatching); + s.writeS32(45, m_airfieldElevation); + for (int i = 0; i < ADSBDEMOD_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); } @@ -245,6 +250,9 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readBool(44, &m_verboseModelMatching, false); + d.readS32(45, &m_airfieldElevation, 0); + for (int i = 0; i < ADSBDEMOD_COLUMNS; i++) { d.readS32(100 + i, &m_columnIndexes[i], i); } diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.h b/plugins/channelrx/demodadsb/adsbdemodsettings.h index 7e46fb27f..86c21153d 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.h +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.h @@ -145,6 +145,8 @@ struct ADSBDemodSettings bool m_displayNavAids; bool m_displayPhotos; Serializable *m_rollupState; + bool m_verboseModelMatching; + int m_airfieldElevation; //!< QFE in ft so aircraft takeoff/land from correct position ADSBDemodSettings(); void resetToDefaults(); diff --git a/plugins/channelrx/demodadsb/adsbdemodsink.cpp b/plugins/channelrx/demodadsb/adsbdemodsink.cpp index 2157410b7..750ff9669 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsink.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsink.cpp @@ -134,6 +134,11 @@ void ADSBDemodSink::processOneSample(Real magsq) m_magsqCount++; m_sampleBuffer[m_writeBuffer][m_writeIdx] = magsq; m_writeIdx++; + if (!m_bufferDateTimeValid[m_writeBuffer]) + { + m_bufferFirstSampleDateTime[m_writeBuffer] = QDateTime::currentDateTime(); + m_bufferDateTimeValid[m_writeBuffer] = true; + } if (m_writeIdx >= m_bufferSize) { m_bufferRead[m_writeBuffer].release(); @@ -152,6 +157,8 @@ void ADSBDemodSink::processOneSample(Real magsq) m_startPoint = boost::chrono::steady_clock::now(); m_writeIdx = m_samplesPerFrame - 1; // Leave space for copying samples from previous buffer + + m_bufferDateTimeValid[m_writeBuffer] = false; } } @@ -213,6 +220,7 @@ void ADSBDemodSink::init(int samplesPerBit) m_samplesPerFrame = samplesPerBit*(ADS_B_PREAMBLE_BITS+ADS_B_ES_BITS); m_samplesPerChip = samplesPerBit/ADS_B_CHIPS_PER_BIT; m_writeIdx = m_samplesPerFrame - 1; // Leave space for copying samples from previous buffer + m_bufferDateTimeValid[m_writeBuffer] = false; for (int i = 0; i < m_buffers; i++) m_sampleBuffer[i] = new Real[m_bufferSize]; diff --git a/plugins/channelrx/demodadsb/adsbdemodsink.h b/plugins/channelrx/demodadsb/adsbdemodsink.h index 90a6fd630..47809041b 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsink.h +++ b/plugins/channelrx/demodadsb/adsbdemodsink.h @@ -97,6 +97,8 @@ private: Real *m_sampleBuffer[3]; //!< Each buffer is m_bufferSize samples QSemaphore m_bufferWrite[3]; //!< Sempahore to control write access to the buffers QSemaphore m_bufferRead[3]; //!< Sempahore to control read access from the buffers + QDateTime m_bufferFirstSampleDateTime[3]; //!< Time for first sample in the buffer + bool m_bufferDateTimeValid[3]; ADSBDemodSinkWorker m_worker; //!< Worker thread that does the actual demodulation int m_writeBuffer; //!< Which of the 3 buffers we're writing in to int m_writeIdx; //!< Index to to current write buffer diff --git a/plugins/channelrx/demodadsb/adsbdemodsinkworker.cpp b/plugins/channelrx/demodadsb/adsbdemodsinkworker.cpp index e3e2d1eaf..c39dd37fa 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsinkworker.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsinkworker.cpp @@ -140,6 +140,8 @@ void ADSBDemodSinkWorker::run() if ((preambleCorrelation > m_correlationThresholdLinear) && (preambleCorrelationOnes != 0.0f)) { + int firstIdx = startIdx; + m_demodStats.m_correlatorMatches++; // Skip over preamble startIdx += samplesPerBit*ADS_B_PREAMBLE_BITS; @@ -202,7 +204,8 @@ void ADSBDemodSinkWorker::run() ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( QByteArray((char*)data, sizeof(data)), preambleCorrelation * m_correlationScale, - preambleCorrelationOnes / samplesPerChip); + preambleCorrelationOnes / samplesPerChip, + rxDateTime(firstIdx, readBuffer)); m_sink->getMessageQueueToGUI()->push(msg); } // Pass to worker to feed to other servers @@ -211,7 +214,8 @@ void ADSBDemodSinkWorker::run() ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( QByteArray((char*)data, sizeof(data)), preambleCorrelation * m_correlationScale, - preambleCorrelationOnes / samplesPerChip); + preambleCorrelationOnes / samplesPerChip, + rxDateTime(firstIdx, readBuffer)); m_sink->getMessageQueueToWorker()->push(msg); } } @@ -245,7 +249,8 @@ void ADSBDemodSinkWorker::run() ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( QByteArray((char*)data, sizeof(data)), preambleCorrelation * m_correlationScale, - preambleCorrelationOnes / samplesPerChip); + preambleCorrelationOnes / samplesPerChip, + rxDateTime(firstIdx, readBuffer)); m_sink->getMessageQueueToWorker()->push(msg); } } @@ -312,7 +317,6 @@ void ADSBDemodSinkWorker::run() } } } - void ADSBDemodSinkWorker::handleInputMessages() { Message* message; @@ -344,3 +348,10 @@ void ADSBDemodSinkWorker::handleInputMessages() } } } + +QDateTime ADSBDemodSinkWorker::rxDateTime(int firstIdx, int readBuffer) const +{ + const qint64 samplesPerSecondMSec = ADS_B_BITS_PER_SECOND * m_settings.m_samplesPerBit / 1000; + const qint64 offsetMSec = (firstIdx - m_sink->m_samplesPerFrame - 1) / samplesPerSecondMSec; + return m_sink->m_bufferFirstSampleDateTime[readBuffer].addMSecs(offsetMSec); +} diff --git a/plugins/channelrx/demodadsb/adsbdemodsinkworker.h b/plugins/channelrx/demodadsb/adsbdemodsinkworker.h index f1c1e7a71..fe9a295e8 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsinkworker.h +++ b/plugins/channelrx/demodadsb/adsbdemodsinkworker.h @@ -76,6 +76,9 @@ private: Real m_correlationThresholdLinear; Real m_correlationScale; crcadsb m_crc; //!< Have as member to avoid recomputing LUT + + QDateTime rxDateTime(int firstIdx, int readBuffer) const; + }; #endif // INCLUDE_ADSBDEMODSINKWORKER_H diff --git a/plugins/channelrx/demodadsb/airlinelogos.qrc b/plugins/channelrx/demodadsb/airlinelogos.qrc index a63c7d960..a024a87cc 100644 --- a/plugins/channelrx/demodadsb/airlinelogos.qrc +++ b/plugins/channelrx/demodadsb/airlinelogos.qrc @@ -1638,6 +1638,30 @@ airlinelogos/YEL.bmp airlinelogos/YZR.bmp airlinelogos/ZOM.bmp + airlinelogos/BCS.bmp + airlinelogos/BEA.bmp + airlinelogos/CATa.bmp + airlinelogos/DHA.bmp + airlinelogos/FJO.bmp + airlinelogos/FPYb.bmp + airlinelogos/GGT.bmp + airlinelogos/GPX.bmp + airlinelogos/HGB.bmp + airlinelogos/ITY.bmp + airlinelogos/JOS.bmp + airlinelogos/KRU.bmp + airlinelogos/NDA.bmp + airlinelogos/NVROLD.bmp + airlinelogos/OCN.bmp + airlinelogos/PXT.bmp + airlinelogos/RBS.bmp + airlinelogos/RYS.bmp + airlinelogos/SKYPARK.bmp + airlinelogos/TES.bmp + airlinelogos/TMT.bmp + airlinelogos/WDY.bmp + airlinelogos/SHF.bmp + airlinelogos/AIO.bmp \ No newline at end of file diff --git a/plugins/channelrx/demodadsb/airlinelogos/AIO.bmp b/plugins/channelrx/demodadsb/airlinelogos/AIO.bmp new file mode 100644 index 0000000000000000000000000000000000000000..51c02052e73efad77c1fa503a603d04c385ef2bf GIT binary patch literal 6938 zcmeHLYfM~46kheG;g|lZ{7_6V!33kxNF*3SLI`O{Ln*{iNR2cWEKpJ!5Ts}zPzp*Z zMGJ+Xh9UwYwB=RaDF~E`f!I*Wqd+O|_ws%o?>8_vJ9l@xOBejna2*LVDb#=XL3MN%f}c6{$=*q*A^1>h>d5cZgJ~?H}so;B+*Yw-{T# ztPrGK(AwG>-7YDnj{Em_p>-gt4*}qrd@+uk-ZrPh?^;q_b(KER1HKUmbar%5MM(+u zKYBz#UwlqK{_s7`&dkuysaI)fanT412O=DSt*tF8FTO=C?^%(*_i@_T*r18=aavwp zrYD1g%wK(6k5Ko+hg`*AIXgQ`1qB5Z5)wi#E-qwgX-T%WwiFN$!1!p_MWdsml#`P~ zfq{W!XJ<#|=H}$&&znboSmJG()0E8W#d{} zS|TeeE2DJKpP88%n@<`4AsvH3skuf4rp zn4`D1H^Fa#9ZD}RFQL7yt&N%MlWe=Xx{`x~16f;JQ&dzGO-@d-I5a&yO~Jvzg5L1( zFw;v*OB49|)(`xIgamo$`-$no{5++nTw&)te6#H44a&+$r}42dYW}N%;mO-wKYHI_ z9)K9CIj`pCW_ccXQSR6L{CuHZR|RXHn3yQo#TtM*J39rwX5Y$pzJAc#FHBcfmMO&V z6vOlENgt}OtEGsbGpv56rkWCCqS<@q)t{*R)-3|&$gv7?e#5YIQbtCGFvqU0Egp;}1K#j&-X0wtEt`vsjFkB}?+{-&DKX{xn&q>c zTTKo145QSfOH@@>#?B>RhVuxq6)_<2gg2A<`t(=SP*+FizC20rSADrvdV0D%4~)+c zrjXYp_+MC9m|#P5p1?+F6K9jA%+%BrjZ1lpCNDcXTeBN2Kh>1w@4LkmYxd2VKq|RW zM896UM$YfNMMplcX7{I!jqP&-gTR@EJQY}beEJDhmX%Uk@?|Q_%@xMTE2dzIyhq=; zkKC$MiuY=@ns+6a$iFxaD3Nm&78VLTWuCPkeu}*QPHhdHKO4mG^83t#x}?~oi;%BY z-!5nV32c8!OQqV%3SFXP3Z^kJF)|LwXMqiH#`$iDkOy;I-Q3)S9Ky%PM@wCa>27^e zX%IR7-Nr_FuP4RDvip)!PFd$UEN~4AIL+<@N*Ply_4oG|aKXI*>)9>k&d3F9Y;4&5 zAvrl&*)26RG|0LfTV7UHR%*%bHKw=^@x6|-hv$e|9qVAIr8s*f{vz}3Qy#~(Buv2+ zF^}W$w6eUsT&v$j>F#V{VWFjuoODLIUn@z8slNWkr2NMa!ACD$h#~BCoH?3jp&?z~ zJ~=T#Hw*q?@wc(Qp0inL3a0Z?UWa|EZ+_q-uCA=C2z~NON=k~BZftBUZx+hE#B^|A zfMHr!RYm#P*M)wJtt?CNEhQnI#pAfh^MaZwn8FZpr0VKwLLP+g1n@oFbHl^K8K37+ zLZ>?w#6;zKw6?bD5;f}Fhb?3Lw5#(0$%dW-1OH0jIrhT0@Qrn3 N=Uc{e0L!kY@E<^kjJf~- literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/BCS.bmp b/plugins/channelrx/demodadsb/airlinelogos/BCS.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b49a16b68904221ac54358dbcbe601519158d70e GIT binary patch literal 5176 zcmeHKUu;uV7(e%R9n}4yyKC33>)6`fmNEw>#w?33CKxdiXQIX@UNCVA!7v^G|05cW z@r6W%2YfM6j4%2M8WT(m1auD8u3gtZthC#}u9uZ=Y_VH+kH2$IcQ-S_liA%vo8LY8 z`a9qK&iT&w=d^qJdTm7e^k59)c?A!n1meUFo*zlLSDWLCXqlK#f)%b6M z64>ap*Vp@B@_$Grz;z7}bemvqJP7MG_5EzH;5#=fy{j~xyt^LOQ#18vXHA!uNSu-g ztvff@{B}iCdS9vkYLwp7h=-Z#h3tq7=s=461cs&o!NTfMu)&3zi=i$SAEG z)&{$+FDIWZb_?Nd5`L77{1;#t>37EMZ%zx*Wy|@6E^}lT2|=0Ziz5wR6v-5o-cojv zVNPOphb?BlP$FsC(*L)v%x5bvGP7Y!1)O8%UrOBnEe8%50^&$h+o5S}XeWuT1wV@} z5`nOr47Wd(K~%SWT!7mkyMzdw!O@s6mdFHk?!VnFhB*(%I(pJVRF#h9p~Fe&bF4jL znC<8t=l%=a{sYoxjnJ%(}MNG8EGKje1yUNT5jw23nWDwKP%W? zpO%g)(tu(+I9+#U&h*C;PC+`RKuzQG_CvWXKmCK;h6URjnlki{D$N6V>&Y4GM+NH# zGaOCt+%?+&kcz;<0e|ZlLWlTtYh&Z-dn8Yrjw^xfV?J*Z2)JS>b#jxspUL_=jQH{t4=bnnYL`tM+W;!xQeOz|{EjqI?-YA=>7-_3WKSY5E(*058E z2Dgr4)Jawyt?`;`OZ8`pJm;aQ9d1}Up)mjTJ3nDZXB!q4R_tpbj=K*AbFw*d4ktA>(s_v&Vyk0O1!M!(& z(lA{vqY88$Hf^{&Vrs_|X`O^1Z;zWVEwa2@$pVp5LqHs16?u+MCd&!0oO%d4A0J0k zBq4UUG$&5{1=I82sX?AUqhV7qE-J_I*{Iq3=yjFuhzd2EfD_${{=Yb Bx9I=? literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/BEA.bmp b/plugins/channelrx/demodadsb/airlinelogos/BEA.bmp new file mode 100644 index 0000000000000000000000000000000000000000..eb8509b86d76e6a2214538d64da0f599ed81c4b6 GIT binary patch literal 5176 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 P;_Op{o*(E1!G(VTWr_Xk diff --git a/plugins/channelrx/demodadsb/airlinelogos/BEL.bmp b/plugins/channelrx/demodadsb/airlinelogos/BEL.bmp index 7ae8d4ed5d7cea0696c0dd3a95937e3c4d371e2e..447a0f05c5eebc47187f296aabe48c1a4b5f863a 100644 GIT binary patch literal 5176 zcmds5c~p~E7Js;aXtA8i;(oMRM>>vGYef-g#j?0n!Eq^;ij=BVQLqKv5J9L5DxfH` zGYp96fKUVh*_1^BNGm02CvC-A61Q{#|lo#a}cacv({o(>Fb< zl8A&YjSYNGKbyhmX>V(&tl;(a$z`(px1#{T zT3XVshd)e7QYw|Sj`sAZ>x7bGl}hzCC52+7m#);snGB`J7LL_?=II{@pxPu{UXXRdl3P%0FeaWUO3q>fij=iK*1pYjJ9EGjkXls~1dMKUNN6c<+H z=k_z14-(>Y6Jq_gZU8bRS(!1xXP*`3535vMHmmGGW{9VUfWy({39?c-a%?wu!Bl!i zq8M-T_28Q!>LNrpMYN>rA{-C-QShNLJ@$$g87uxUWzFNlONS4ZW&H=_thkt-)|U3B zmsfp`B!vc%>IfVbD>eKowlc!wf~tZ%A)oK-vhA0|*nj;T3V2y|R`l63&mQH0T$!5_ z7aZ7JM;IQ~8WZa)myfJpz|u#QU~d72K5O*#>A(!Q+ zBmqvWthgN#lz%4`j!!GGJ}xAC1+OWJ6Nj*8eSckQI43l3vCe zxBcxd|8M?pui)Jxe_8&WWJO7#w2!I16xc>fhu-iY8vc^O!Q7gC73dHw5k5Q*<{?rTjG+&<8g6lEwbV_{3WEGO*`ZmKvb}{SJ0m0zw)IiOj!(@6|f3^%EC$lLICI%pQu35pR)1WER&wB+zJ!CRA1eCza z%YH3@n`XZ6WIhFy16`eA3#1b9jzx1^=1)IlXZ7t03rjt8@C!?sRGJwbW&56ihvibh zH_e=CrH=~JQeYfvTdUi03+TRahLP((=Gji3cw+k&!0+FT{0Jdp#nXBoXbu#dnL zQ9n`#MQVJ6CIqVagUwfsL)o#nz*lqG?6hlPpCT0SwF@-e4m@dNh^TFCAY;${s0dhe zYS_=P5uks?>i|^2^02bro-W)!-#l>~aAM_?0WKFZAFMB%MzjB5(ov_+q3XNUVXfhW z$9L~2EzzUhynaz7aT3v*tt3QPcG~f78Eb~YQ{lA9&f|+$)|UIrI}~+-wBtE4%76d zVo7{Rz_0iR?{i&mJW!xCi?pS=9N zVFnr*fmCnvY~#aUT1h2R*^o@3P^O1p{sbY&a|+T@fPZ6k6}_`#^*D6Q(Uw$8kPd2d zTYM#dih#PCo1IJzz&QJ@mqX$O(|b8s!&2^Cy95(F$;pBf>#=%CPF!?eN)qJZp`LE` zrUttF*NjKW=L11`=f`v5*w>er!ln?4i{Ll__$W0Q_(%C3>wHNh*VjEtPit>%06ZqZ zA9&vI^=hdj)D;))vs}8t{QW_J;9+vYDE~@G7FUl)KAYBoLVIIBuni0dn{xTcf!`z#w_Z2-#dJi%Vd4upydB{W$T3$$ zyEpg4rNBWof2#@L&o9X3@}`<+^-s(DdwcO_OaQZ!iS=znBKYK93WeOzpj2x72Oy;S z`o7m)z_Goot|Al_kO(zg784(*yO~s5T=b&6w1?cR>%-`somF|c&;+>vrmW##QjArZ z6bi%wP-tr)4hpqzGWf`Fy-#}bEle5NcO*CnNw%9k#{^M>j%&N*WJn-Pf>WG}=+#d& zNdf92k-)*k2c5<{zgywK?VE7>YG3>R-(3v6{6mDBhV!Z literal 5176 zcmd^DX;_rk6=vGlG_`5-Bx=wmpkM^G#;AZsM8FcQS`s3zwFw$z8B~w~WUq(Kb|@Qp(rlgb_KC87yV`Udhh`w$W-kG)y&&!7_M!Ui6sg`Xp+}(WKHdg zwL1j6ZN$(hx9qTgp55{(J0ropObq|HV1&Hj5fmLx^dHZ3VmjO^jm zvNID|i4jhpf7JD)y7)$9b2-at-3J_2c0p_iZR5w4S;<9lm+Kg5qXT_T>lbmW%3Deb z9y8MJ278^|@(Jk^+wQo2ab5o1E8p!(aJHHd3*9z<(p**q{J=beza-zy;7`DRKivP4 zI2mC;Sue4Sax3C|$Z`DM?!wli@+@>WSeUTr13Ht#}*pa{7 z4seAKLp_k}O?_5h<+%0_q{G=>Ix+5Js!KQ5Bk1?-gQ*)>4Gl-$S*G`){AFVKMB<0t$G1ack**#CdWe~<2kp&w8G9rV;$ zS81n7x%`h^p@&WFw0~2Zd;3m+D^=%r+}aA*5cttRb%kY96}3~dA!vOjcL|)}@s;pj zKIgY{-HZO7ByR@~eRb)$B<$!{G1P5xU(HmgDW7cWoF{Ix#4mw z(bXFDkF-bf6a4qZ;`XZ2v7rITWd7$yUJSN0!YuUIc4WteJ)2T}P9ozRSHF)V28WK9 zkyb|y`_duf6rYp$P+xPy4F0+%`C2ofg}qoNgNJG9)O1PJ)WK7d=Y4bapC1zp+H}zU zJyJB`yc^7JI)8UUgMz2N;9h{aLCzIFC_zz$v0)?qJ*W|nts35@p9y(G5r=l3TKC73 zx(jhSqI^#4E<^@8=q}_Gm6GSN}$CS4vXn+vI=Q}0|EtwSyz8B$9VzH!z@k_1DZGws)P2g zJ+`d~+)dOkGr}Kd3T@+(2&+9a_{Ri_(AbGe&J5b8ZE{NoF`}T{a<2xs>Mu)lwqgXG zl?VkG>T7Ap@TcL7>2GbU$V}|0W*wE_^2a%$X$;NqbKhEiBy6u{g)0 zdC@^lr3E0x(ZT-C`YIeBn8mGol_ywG=h=gbWi(8`+Zm^UJ9F} z{UazigHRyKL;sCDhrh8+{`s!48w?^~uWhsZ|Ju?2Sqc2O)wDk*_WwUOUN;xyids`P zBhNpACa(sBTkTf9J1U#KNuI+$F{xbJT=q`bDT z#N|@ivVoNYE(D3@Mg@i(GEvD6Wy{yfbNDe_P$J)NE8>sNalZ1L>YQ750?#UIeij)A z!420Ra94k;HzNN<0u_Y4%?-((_PEue)Nw$*)rpG1EBHHl6*;V_LEh`}tIV7qudm<- zr1TtV3gZ=mnIAacghCZR{uatDe|ZOZ(~SA0SH&+GSK!YcK5@GLBAP0G-2c+Er7dl9 b*S`53237n(+ukK-vEO(Lm}lX@e*pglGKPdR diff --git a/plugins/channelrx/demodadsb/airlinelogos/BELold.bmp b/plugins/channelrx/demodadsb/airlinelogos/BELold.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7ae8d4ed5d7cea0696c0dd3a95937e3c4d371e2e GIT binary patch literal 5176 zcmd^DX;_rk6=vGlG_`5-Bx=wmpkM^G#;AZsM8FcQS`s3zwFw$z8B~w~WUq(Kb|@Qp(rlgb_KC87yV`Udhh`w$W-kG)y&&!7_M!Ui6sg`Xp+}(WKHdg zwL1j6ZN$(hx9qTgp55{(J0ropObq|HV1&Hj5fmLx^dHZ3VmjO^jm zvNID|i4jhpf7JD)y7)$9b2-at-3J_2c0p_iZR5w4S;<9lm+Kg5qXT_T>lbmW%3Deb z9y8MJ278^|@(Jk^+wQo2ab5o1E8p!(aJHHd3*9z<(p**q{J=beza-zy;7`DRKivP4 zI2mC;Sue4Sax3C|$Z`DM?!wli@+@>WSeUTr13Ht#}*pa{7 z4seAKLp_k}O?_5h<+%0_q{G=>Ix+5Js!KQ5Bk1?-gQ*)>4Gl-$S*G`){AFVKMB<0t$G1ack**#CdWe~<2kp&w8G9rV;$ zS81n7x%`h^p@&WFw0~2Zd;3m+D^=%r+}aA*5cttRb%kY96}3~dA!vOjcL|)}@s;pj zKIgY{-HZO7ByR@~eRb)$B<$!{G1P5xU(HmgDW7cWoF{Ix#4mw z(bXFDkF-bf6a4qZ;`XZ2v7rITWd7$yUJSN0!YuUIc4WteJ)2T}P9ozRSHF)V28WK9 zkyb|y`_duf6rYp$P+xPy4F0+%`C2ofg}qoNgNJG9)O1PJ)WK7d=Y4bapC1zp+H}zU zJyJB`yc^7JI)8UUgMz2N;9h{aLCzIFC_zz$v0)?qJ*W|nts35@p9y(G5r=l3TKC73 zx(jhSqI^#4E<^@8=q}_Gm6GSN}$CS4vXn+vI=Q}0|EtwSyz8B$9VzH!z@k_1DZGws)P2g zJ+`d~+)dOkGr}Kd3T@+(2&+9a_{Ri_(AbGe&J5b8ZE{NoF`}T{a<2xs>Mu)lwqgXG zl?VkG>T7Ap@TcL7>2GbU$V}|0W*wE_^2a%$X$;NqbKhEiBy6u{g)0 zdC@^lr3E0x(ZT-C`YIeBn8mGol_ywG=h=gbWi(8`+Zm^UJ9F} z{UazigHRyKL;sCDhrh8+{`s!48w?^~uWhsZ|Ju?2Sqc2O)wDk*_WwUOUN;xyids`P zBhNpACa(sBTkTf9J1U#KNuI+$F{xbJT=q`bDT z#N|@ivVoNYE(D3@Mg@i(GEvD6Wy{yfbNDe_P$J)NE8>sNalZ1L>YQ750?#UIeij)A z!420Ra94k;HzNN<0u_Y4%?-((_PEue)Nw$*)rpG1EBHHl6*;V_LEh`}tIV7qudm<- zr1TtV3gZ=mnIAacghCZR{uatDe|ZOZ(~SA0SH&+GSK!YcK5@GLBAP0G-2c+Er7dl9 b*S`53237n(+ukK-vEO(Lm}lX@e*pglGKPdR literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/BHL.bmp b/plugins/channelrx/demodadsb/airlinelogos/BHL.bmp index 80730b99cf6e0dbc8f5edb12a044fc190c38a722..1e6347616092ba23cad3869348948da9c30a49a4 100644 GIT binary patch literal 5176 zcmdT|c}$c?6#qa#5fmz*cvoYqHW4X;)kKt_V!UF4oPVfLEk(*9g%D7Pc-2-3qCpXX zLM0p?fS{sLba6#M6j`B4KtOhJmur{h+yj=izumFlF0fT-j0uz3FYmp1GxL7)-n=(p zzkQV{rEDwlU4ox8ehQHmWsWaJX@mLNg8Y;MeBO_x$z_tR_V$yC>mi#>SA~)T*kgJUl!=@7%dlF8^SRrKP2_0>Ld1gR@3srP(^&cmCj3<2zKQO?idGqGcn{D2_84_Jx-P^Zs!@ZyZh8~6W zka&7}4h{|yA%nq~Jb5yNb#-;&;o%@GEG)>-s#UANu3x{NusBc?6B9_TUAqPeqKuqx zSy>raJ3BiJZP~JgC~N$x@HdpC<%BHBKW>wMOx5$kt!o$;F|+(?(3tSUdp$ipWXrQ> z&%zG0h=_C2u1Lkm5wsn||K8r-$Y&(Bp|E1b3IKo(i6(-d#bS|lu3x`SrX%dF zt*s$+aB!%ttp!xjNE5gP2td%d3;zE8yLa!Vw;M*N@MGX5^Kog47wd{A>&lO$S7d_N z`(7rj$PT6P8IG3G{sq4Go2m#6J=wIX(mwnT{jV*Vl)_`Sa%w9XbSJ#*7(#eSN1+ zodS)Pk&)5T(qd+222C<$*mns2;^OzNP9ncwB)cgmo-$>MudgqRMzKVItXsDZ zm*3IR5vM~?>FMbK3^cJ_OiT<4B-TNQVFlcLfWL6z0!|iTLi_pX(W7*hxpCtL!fK?c zkPN{Op7lZ+=qvE~sonQyet-|(f4?BWPwefqEK@<96p~9c}YnL3NS z8ipW3)&$7<`g&5#F$DpYnVDHpQK6jl9?Rn4B#}r6i!VG+3;^BV-`~{KL=UMG!||(+ zftC-7t8e}K;KYVf*<*xKtc?YVumLTt)ot$ zXrY+b)YPa8)oIjxL~F+1)iroLQn=cx?FoaM6R4N$PQADpzj>47yKe** zOI7{b1%kD!JG#4u?1=P>u!R3%G29y#7N!VvWvCC)Q!=;|OO_~}>f5$$8#zi#)SXES zKMSE5e_5%-coKW&G~N>i?^c*ek~{T=`6rLfXEDnvpFE>`Rq?Z&zsld#s$NZqa1?MQ zUPTQfS9IpgnIx-?v>16F^$8gvIy!pf=ogS^#{axbGRKrN-@KW|UtgRdY%ERRM_uvJ zQtwyy>sIDQ(1s%Bkb$=T>WVJ&8x-&D@z_3r zzqqjVR_L@#PSl&nm&YT#Pui>*fBAF8{hwvh`XH||Cs6<4+3nIk;V0J`j|!UcGYZ5; rdTcjGK?AF_qj9{(_GtW}0YCny#AHbB-NpOq!#@>9v(PxzL8<-+TSd>^ literal 5176 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 literal 5176 zcmd^Ddu)?c6#urao$I!CeXiSJEqiZ;t*;S{8dQP^KB6KK1ra0?H6c-BBmrY$q68nH z_+ZAMf<+6yGKIti^|>5;z^cIW7?o#rRL3*}t+TrfZm|RMN;ebv+ZGpQog( zXI!S8i7rPaaV<+~V4{DcGKB6;^s^;h2=k_>De_)OCcoD(@CP;uL?t0GH9=9L#t3Yo zTlg_aYov|Qj^;TvcE*{v_8Ok+nM;eF?a^=cB>&@6eKEXf9gSnqCQt6xKF#i%(vy>- zOJtR}jwSy!ox8PHzcFmD;RR3joBd>e9ZR~%G`qcqbv?PE@;7<(FM6b>rmz~wO-Pgd zG@kQDzaC4VQ06&f!}C4LuSX;`zT7Rnuwt%h{EX@4UaoA{4c$9~5oqUN){X(`A5+l7 zl;yJBWw)j~VvDJJHUNGKH($`A9f>jYuHLIMK3`ZC#oHnW5B6p}hA4+tv)ZZpyEi4T3D4dna_Tpuo zlIm&T3(~t_wHrxc$(R+TASar&uJq&M2~MW|bO?{Z?SkVXJUT1I&AOd~;`2TPPyI<` z0}J;LaZA^B7e3r|8!EoPQ}eM`a&FpK(N0+qo&r#@%+^t~ytC**qJouOh*f}!mUp52 zP{1%i^O3jszN`FFU;z8&hsLm)=wvCUZy{m@D`)o3NLbdHwS9ofq=5lkiXP|`NC-Sa zc`OAK;J=}E;UjJUka~|72Sqf{wx*lYU1UkXq38sZ5?2%UqMT5uCT&;=AWO5~>Q87P z6~UQ)Y+U}snEVJ43R`|~G~?hXU>t~;a^_aXccV1PuO1%54DozV^RlC3^20N$JWs~A zqv*O+9_)4Fk z3J`x&whOA@juh83;02Hj5P%8~5K1xgy&G^4?uGKaRun~WHH3}l4;yHl@HhY!;13Dv zy+bG>lv_}On(D>4q&?+~|FW2CMWD5rJMW*#ya4+VxA^)Wig1mucy9&-aqDOKaMCBT;15U2hAO9&YVFhd%nBT!U@5lVxS{4(R(sMM)U zLSOzH2~!T{`NNg= z^8_4(G$}I)aTH-MvvlCbMvwut`YpY}>k!$YaVfqTNw~sLYmkq}&{L3cC=+BKWkK92 z5MTW3q4X`Isof@_D=h}e91-pajjKZ6f>sI@1Q!4xselDIn(okV?nQpV0LfXO(Jb^4 z#Nq-<{(Blgkn?)K&_O5@nFEamwTy9BL45Z68)?~(DHp!hCp19oLe-$M;2?0qN5~pMkWn~>^&U#{T3^XMR}qOY1u|VIG~Abj#POv- zy!JyJuqS)_zzp&!oQOtjLR$hLSkQvNBC+XxCZHA#2uH0_N*121sSauif1jc^qGpz} z?Yi(dIki=2MgRoq$0tlVEr>b49Rv6jC!#?37l+$B;tuRbQc2Dc5FkXVFXJV}fss_a z4mGi$@qQP;!qk&fs(nMDqLg0^qt8RLNX$6yEVXW73^@0*A!;bn;}*DdhXl*RUx#^BFds;Dfy|)lFmmp3c&D0uDWs+-B14oD`J?#( a*+1WZ|1kQ0|3Viu-w40@l{PW_4EP@doq&h{ diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHL.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHL.bmp index 246bb2629d5411df3e1e1f88d0c799f7b066697b..3f2abb69119b688ea8db63d3a71b797bae40a5b1 100644 GIT binary patch literal 5176 zcmds*X;4#F6vuB^tkex67(^^v!jg?Z5S3kIO@f86BoMX$VQENMLS&0nELO3V+Ezc< znNDZA`l0Q#o#HZ`0c`8kR;Us|3{WYkZIK9q#VLw;JueS}9jg^(2Bw+cdvo4-=iS_M z?)l%BNqF2ATV(wB!`Ty#WH@ja3E9ILAv3u6)PgvS4*b+^SPEE}A6pcbO8!TW_ALra zCI7qkrWb{!l0Vtz^F?8S^6xMp;AbOXnD!L#oc}i-id3oEA4hq+>Io<>Z=Wy7?dSx# zMsHJh^I@!akFGp2Vcv2N=`hrVtvGsnZPiR9S)*V1_5{*mkn`%sTjbg~ztxA6s2hWF zkj@!aymQ-T_rHt`-vuLBeR2m~!iZvFm|;;s)Fb0el9q|I40Q3IfCqQd>~(g1%`UEba~xgA$d!5)x&T_LAS2W?I4zi8=WXkh%@ziV=t*oDfg&V2NQ^r!7~A z{FNmgb0|BMk3ga9z)^H4743lHnL(5;40Red2K)+hCGv+EQ#bam**j+a@+i4vWUUg% zE^m1GM|V&^wtC-~ZT<~%sh(V-w=KM};_z+rAMZgG$Q61BGx|sDiiV&2>@VnT7{Ru{ z7!2{H`n4q^)^(%S^<&n%MhR@HZ_f5VhGF;Nm{o!4(qs?^k=Rdw)6#hBm}qb%?v>$Qz=_euw#)bxgZ@_7iOk8u761S$1N|>VrwTIj#%5w~cs_ zx;>X)g0snqt7E;+;_SVZhsTMYhe%^_wd9?8Jb%+W!f2#&JsJw7shb#T@rzIbk&pZC z+;rLY0BMMCeSSu&pO-o{z9uV04E}tHWb0;L^cQh)rv-u*KA)hK&u``N<_)qxe}A3y zcgN_#^}_4x6XtN(acu+dszc&6SNDFHIw1{c5IgxW8pgitQ}*1H>G zubOlOhGY038pP~m!zL#LdsEY? z-Wo@}@H#X&ZXYD{0(Zf1j2Z%In14SFDlqwBOj~$&^cbA{224&cs4wU&Tkhh0H`@i- zK|Y77%ab`YO}4nPyeNV0e4wJZATmfA=+jhHmc*uNawVXPc!u)q_l^49>n+U{ge$_`4l`4p@A1*V+Gy=_wHT zs-|%?1Ui~@b?VOJ%2K>(bvdc~l?6hE%R#kL z77>sY%sp6HD)OO%D<^eNQMSm}qp_?|8n%tYI_Awj;m!J*&1#;3 z+02?hOC|qwe@1SY|0_k(viPWCUg$nWzBGhelaahfmXQ_6X^`g@$AuS0hcw9ZGDEm| zVg3`NH~&}tpSjh$J}*Pb53fp#*JO)|V?%dki7S%$Dq)O9no`UQt4>R-%}kcZhSX-K zNVf%7s@pVm+FH%|8ld*+St{$FwUu2h5hk;#NbEW9TtN@N=6CEm&#BwRw m5mA;9BV;(KQw8EJfzL00*TUkMrRB#278aj8-QQ>M2jJfl5wUgv literal 5176 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 diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHV.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHV.bmp index 603dcf85eb1d1381352f726966b3862d4db87990..35fe87c43e3edb39fdc34070195399953423c8fa 100644 GIT binary patch literal 5176 zcmd5x_BHACFx*-Hys{PTbj8buF-B6aq#H~}?u~P)B z;MnRo)7r&RXIy3!v?Hz+0hNR`1PEaj5{O7~1Y&N_&C>^hbq3@InJ;f{&O7gNzwd01 z`Eil1$oh$ZYY==tgD){LkULxvV#1H}Hq_T@AeUmxI6%7~}4G zecsm9ITHI!A<7n^9LZQ>9PwX~isEFiB>*87?naA~k>cb+wf-)sV5+IjOImk4fRj0K zEL9js{AcGRNtG@uQU+9jETB|4a9XO?{{t#KtJdajUz0s{xiF6S^R8pB+^1p3l~M(F za4tYOEZ9YIL3wIXiS9PZ1#Rv1-3iD1Y_dMMBF2dSBMSmNwgMJ(PXWu5cVW0^vBe=c z(ouPldjor2YngRCEk?;*HmD*f6_%th_nwL_(cc3VIx4Gjx5sCTZL{1*UlB-r;<;dt zk-x8FICuv-9kZXaZuTP$MrGLHM7N9VwWmO7bo}W#Qe)ukeE69_F<|GM=|SZfhpHS=ZM(Q7c$*P3?#|!3Sp>2ka{XAeH&mQ#sGJX+tzkQ`76$u7s2eZ zX-Eam#GhH}l+}fru^`Pj4V6$vxI5Xkl6|!o>F~tFr?fM5_w|EhTQ%GYbgyFP_0s(5 zi3Agh6By>Gyu{DLp1JL_vQwg!{N-==1*nK6sVv2*sM5va*H6@06vrv{3#5U7`F9|tQ*ds5(3hJBc8!Mc$I$xdt5io&Pk3@@`kFg8$~6f zy(br!Hx+c5yE}VLBLxzcVWhH5npY2JrTD{%C6lVThfKWvoq`<(m+b^@8`|uDe}QVS z^Y*jWcW8JKW{h)#%*$8e{yTNTso85(%klV0>>n5u+`0q5j>@e{5 zb@C3HczZi3@Z}x<$DdLGa=|t*+(~)K+8x`&jwMGcU6!W~j7e%nM5o!T+V8w_(%+lGi1R06l0)Il~|+&1bS9NsiRu#y{I9;PeY7it;DN3z)b^* zAokOW{fQfe08b4RKcmdz8>y4{S5robs9LzX1=VAu#iXYIss`$x&i~;HCPEW@rttP% z4MC=ar)fGcez)#0JBDd=}R)X9 z4c0v~Q~_;=JzZgTR9bvz>1ZP?Bt9DU%|4QMbnu7qhyLdxBjWA4CY^9Vei&m zhV`2a8@7xLXd=}AV+^5S7QA{t2=mG}Cx+BjVa6j1^TC^^?wgtS%!H2`GYY|Irgnpj zVBR+qV-YyNHo{Y^JLVzz56qcN7AHK4n^nTUg}txTMrN#DDq{_a`6o#rgx!yS#T&Xb zz+7G0pRlPVc&08eR2MX3#2BOZUpj^#uyCBaoSRV$+3tHu4RszTXAft-bPtJnYiB7i ze^~JH%Pq}QW)jXbBI{?)9Sz12e_lRxxXL-1@o{pSATDlE9)6A^{&d*kWlkz%9R6cXeG7@X VO5MM1W6M-)%*T*9r3K8K{{T6dCJz7r literal 5176 zcmd^Ddu)?c6#urao$I!CeXiSJEqiZ;t*;S{8dQP^KB6KK1ra0?H6c-BBmrY$q68nH z_+ZAMf<+6yGKIti^|>5;z^cIW7?o#rRL3*}t+TrfZm|RMN;ebv+ZGpQog( zXI!S8i7rPaaV<+~V4{DcGKB6;^s^;h2=k_>De_)OCcoD(@CP;uL?t0GH9=9L#t3Yo zTlg_aYov|Qj^;TvcE*{v_8Ok+nM;eF?a^=cB>&@6eKEXf9gSnqCQt6xKF#i%(vy>- zOJtR}jwSy!ox8PHzcFmD;RR3joBd>e9ZR~%G`qcqbv?PE@;7<(FM6b>rmz~wO-Pgd zG@kQDzaC4VQ06&f!}C4LuSX;`zT7Rnuwt%h{EX@4UaoA{4c$9~5oqUN){X(`A5+l7 zl;yJBWw)j~VvDJJHUNGKH($`A9f>jYuHLIMK3`ZC#oHnW5B6p}hA4+tv)ZZpyEi4T3D4dna_Tpuo zlIm&T3(~t_wHrxc$(R+TASar&uJq&M2~MW|bO?{Z?SkVXJUT1I&AOd~;`2TPPyI<` z0}J;LaZA^B7e3r|8!EoPQ}eM`a&FpK(N0+qo&r#@%+^t~ytC**qJouOh*f}!mUp52 zP{1%i^O3jszN`FFU;z8&hsLm)=wvCUZy{m@D`)o3NLbdHwS9ofq=5lkiXP|`NC-Sa zc`OAK;J=}E;UjJUka~|72Sqf{wx*lYU1UkXq38sZ5?2%UqMT5uCT&;=AWO5~>Q87P z6~UQ)Y+U}snEVJ43R`|~G~?hXU>t~;a^_aXccV1PuO1%54DozV^RlC3^20N$JWs~A zqv*O+9_)4Fk z3J`x&whOA@juh83;02Hj5P%8~5K1xgy&G^4?uGKaRun~WHH3}l4;yHl@HhY!;13Dv zy+bG>lv_}On(D>4q&?+~|FW2CMWD5rJMW*#ya4+VxA^)Wig1mucy9&-aqDOKaMCBT;15U2hAO9&YVFhd%nBT!U@5lVxS{4(R(sMM)U zLSOzH2~!T{`NNg= z^8_4(G$}I)aTH-MvvlCbMvwut`YpY}>k!$YaVfqTNw~sLYmkq}&{L3cC=+BKWkK92 z5MTW3q4X`Isof@_D=h}e91-pajjKZ6f>sI@1Q!4xselDIn(okV?nQpV0LfXO(Jb^4 z#Nq-<{(Blgkn?)K&_O5@nFEamwTy9BL45Z68)?~(DHp!hCp19oLe-$M;2?0qN5~pMkWn~>^&U#{T3^XMR}qOY1u|VIG~Abj#POv- zy!JyJuqS)_zzp&!oQOtjLR$hLSkQvNBC+XxCZHA#2uH0_N*121sSauif1jc^qGpz} z?Yi(dIki=2MgRoq$0tlVEr>b49Rv6jC!#?37l+$B;tuRbQc2Dc5FkXVFXJV}fss_a z4mGi$@qQP;!qk&fs(nMDqLg0^qt8RLNX$6yEVXW73^@0*A!;bn;}*DdhXl*RUx#^BFds;Dfy|)lFmmp3c&D0uDWs+-B14oD`J?#( a*+1WZ|1kQ0|3Viu-w40@l{PW_4EP@doq&h{ diff --git a/plugins/channelrx/demodadsb/airlinelogos/DHX.bmp b/plugins/channelrx/demodadsb/airlinelogos/DHX.bmp index 603dcf85eb1d1381352f726966b3862d4db87990..46db2c6beed18d9c6f8f6550b42ec74ccb9c56f1 100644 GIT binary patch literal 5176 zcmd^CdrVtZ7(Xp^Ql8~fD3mgwy@m4Hj4_0u#))w_1hZ*aH1nS&GF?<4X7hnK=X6_^ z=zOpxZvH{yW)@#j|8Uco%;?6%(E@$Z2k(~hYN0$`}tB8KL>r>DR3 z-LL0&&iDJyy=7G;VifokL#u+T8ZH9yP%5+t@!`j}k?a)!NTX&pgW)wlwgFG`XQTVe z&AC*EG(w#z)Z`|%b7KDw{>zKQ*aqf*_-6dMDvKg+>+zrSEOhBTpEnIxKG;PkY$g7; zTc=+=)K@ImW<_hHe06s8X3KvKgTUGY2AyC{0i+|Gg?KJ!c=&H^`<;(ZIjYOes-zAn zzb%VH{VOiaPz|ocV-uk!IzAbDekS7j01oM&7VUY^Sr7>bYLa$xFpR}t!DK^V;yn*>+A zs2``)j0TM}fwLFG9{YwlOX_<`D0hlYxA7)HvSQAdVMej^f zbVe4Rj3IlEY*(v12iAP;I+sz7jH&~9;1X4%6SoWArnPnlMqMJ^)Dw8dc2#Tz3 zMK*C`O)0g2_<05wK5nYLZ?3NLx`BZw|YZU-!n zXH-RXK^p{#I?^nWtqZZ|rrDea&%om9sMlPCfAEY5bV4d!7{I@bz zPwiMtIXEIKA5447k+yHeq)!f|SJZ~PEW$55 zg5P}Ud+b3SK}S|Lhz43w9UJ~K)U=Rc?V zw_?%z?j1-A)d=W?8cdztK+@sq<3626RyYnB*`tH3USJeDvfVb2M#N1&s33?#Ofj4t zCMNU#{vZe)db>q%-AD3nISW>i4bwH~W=}QRD<3cxrFKXoIX(X+ItKC_Dj7{%<#f*) zmUUkr6h)*ZXFEI&ME>f_D((y31tO0-JB@6hBab|%TTX-ZDCq8NRnNAo-fcg7vv>Bw zPd2_X+aj)YLJ$&a-T99(Gdbb=@oVS)$IS|^^q&IyZ^y6|{MN;_jW9PY&lplyi+LJ` z|L5{uEq?w@KjEXpyxRc!*=Udv{1!g}+rW7Vgu5dC@UK7r*_7~k{p!}4rZbMcWhR;{ z{=p3VZ#!Xe5S%I--7S|^K-toTkeZZ!+Up`=s1qvf4JSo4Mz*v X?7IMc=gf(Q!LoY|kojD{|D%5Z%Ads1 literal 5176 zcmd^Ddu)?c6#urao$I!CeXiSJEqiZ;t*;S{8dQP^KB6KK1ra0?H6c-BBmrY$q68nH z_+ZAMf<+6yGKIti^|>5;z^cIW7?o#rRL3*}t+TrfZm|RMN;ebv+ZGpQog( zXI!S8i7rPaaV<+~V4{DcGKB6;^s^;h2=k_>De_)OCcoD(@CP;uL?t0GH9=9L#t3Yo zTlg_aYov|Qj^;TvcE*{v_8Ok+nM;eF?a^=cB>&@6eKEXf9gSnqCQt6xKF#i%(vy>- zOJtR}jwSy!ox8PHzcFmD;RR3joBd>e9ZR~%G`qcqbv?PE@;7<(FM6b>rmz~wO-Pgd zG@kQDzaC4VQ06&f!}C4LuSX;`zT7Rnuwt%h{EX@4UaoA{4c$9~5oqUN){X(`A5+l7 zl;yJBWw)j~VvDJJHUNGKH($`A9f>jYuHLIMK3`ZC#oHnW5B6p}hA4+tv)ZZpyEi4T3D4dna_Tpuo zlIm&T3(~t_wHrxc$(R+TASar&uJq&M2~MW|bO?{Z?SkVXJUT1I&AOd~;`2TPPyI<` z0}J;LaZA^B7e3r|8!EoPQ}eM`a&FpK(N0+qo&r#@%+^t~ytC**qJouOh*f}!mUp52 zP{1%i^O3jszN`FFU;z8&hsLm)=wvCUZy{m@D`)o3NLbdHwS9ofq=5lkiXP|`NC-Sa zc`OAK;J=}E;UjJUka~|72Sqf{wx*lYU1UkXq38sZ5?2%UqMT5uCT&;=AWO5~>Q87P z6~UQ)Y+U}snEVJ43R`|~G~?hXU>t~;a^_aXccV1PuO1%54DozV^RlC3^20N$JWs~A zqv*O+9_)4Fk z3J`x&whOA@juh83;02Hj5P%8~5K1xgy&G^4?uGKaRun~WHH3}l4;yHl@HhY!;13Dv zy+bG>lv_}On(D>4q&?+~|FW2CMWD5rJMW*#ya4+VxA^)Wig1mucy9&-aqDOKaMCBT;15U2hAO9&YVFhd%nBT!U@5lVxS{4(R(sMM)U zLSOzH2~!T{`NNg= z^8_4(G$}I)aTH-MvvlCbMvwut`YpY}>k!$YaVfqTNw~sLYmkq}&{L3cC=+BKWkK92 z5MTW3q4X`Isof@_D=h}e91-pajjKZ6f>sI@1Q!4xselDIn(okV?nQpV0LfXO(Jb^4 z#Nq-<{(Blgkn?)K&_O5@nFEamwTy9BL45Z68)?~(DHp!hCp19oLe-$M;2?0qN5~pMkWn~>^&U#{T3^XMR}qOY1u|VIG~Abj#POv- zy!JyJuqS)_zzp&!oQOtjLR$hLSkQvNBC+XxCZHA#2uH0_N*121sSauif1jc^qGpz} z?Yi(dIki=2MgRoq$0tlVEr>b49Rv6jC!#?37l+$B;tuRbQc2Dc5FkXVFXJV}fss_a z4mGi$@qQP;!qk&fs(nMDqLg0^qt8RLNX$6yEVXW73^@0*A!;bn;}*DdhXl*RUx#^BFds;Dfy|)lFmmp3c&D0uDWs+-B14oD`J?#( a*+1WZ|1kQ0|3Viu-w40@l{PW_4EP@doq&h{ diff --git a/plugins/channelrx/demodadsb/airlinelogos/FJO.bmp b/plugins/channelrx/demodadsb/airlinelogos/FJO.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3f3ed806132c74971677f5b1cac6f2e5473f9945 GIT binary patch literal 5176 zcmeHLdrXs86t6}XUFMu~M&0I?EK6p#EZP2;naegamt~7lHXrze2qrE@6PNj%517iU zv^J%sJj-|^Z=^tJ>1az!OF=;>AQ+yOm*G(!h1Qm~xL>*OSwDu6|BU+Od^hKud+zzp z@7#0GZMt>G*Y7Z@7k#uLg24z}$_QEW7I(wC@J(MN_+3=#^#k)|;d#M7UwjMI4-J|l1U1`!%2@e2 z`|TB+wX3)*USqwthR+JoP1+oDy}fAoDTFst8#jNI1n}>#<*#4OTfUfi{C6pei!vY# z9lx$x-(l#c84(eBi9#b)x(JL!Q9e3mqAc4w4aM^E!jiHY{auISai)784AkfwDKjwb zon7@!EnqAbt6Z%sQEE%dv=|NDeeP!9@kQeEc3tD7oqm$XC(KwlFl3~yqC}(7a`u#B z<#IOgBMWaVWhKVxsae9%@pGb*WU3095fPSWF6t8h;J(Zgg@`SnO4H zq@m|=3gGiHGaNpJskwekL3C1Q6=wX4EF>sN<;_^zO} zb=cj8j$aUeqpae#y9LD~*}T{kCwkQEL#6=fVlYpwt05x7VhIx3I=hJIa5(cNiVHzu zJ$?Olhl4LnLy9NN7BUNOxkZJwFPjZkpd#3h(ZPNtsMp;lJUX7(4}BL zDJ6IPTwYS#{=vHN)o*gp5q{a4j)qFv(D5VR;!^eS$k_16=*XA}NGVf-pAspiyRRSk z@6rC@YmmMdBUgd zu}_#iJAN2zH9enw5)1t32we6|TA`=o7pCR;hYIj*R3j?WVzrWhFcSRk86i`^592^? z3~D$i%r#!)M3rfuC?bp1#^ejnUcKJb+DNPy2Mag-@zF z$ifBT$C8#7%5h%Av=B}rB8h&g$5~{1w&-#48j!Zr=7Va}ztiX@{r>UF)?D8p7VWCLk@)?nkfvEZihM-3Ph^knw&MGKD zTG3N*AIr)raGTP6&L^72Y@Wa6EnCE_(Du;r4;n{sho@u}rsWnP==@?i`ZICV(A@gJ zTZdU36WnkjsWQ7zrqEPT;4uaK$P3Ot6%Fc3fA=0G62{?l;=65b9UeaG8k?~;w@@Z8 zuk0UmfyV=Vq0ALwdcNeQSe_}8Ak<8e)I58q5VNO`DE<@2q@R8qL&yL0WiQxlY*gJ# TjUU_j3jYgM(+h-ye*pgjg;pP1 literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/FPYb.bmp b/plugins/channelrx/demodadsb/airlinelogos/FPYb.bmp new file mode 100644 index 0000000000000000000000000000000000000000..43437ba6dd8e2ec2f4b2851d649aa4e343d564ca GIT binary patch literal 5176 zcmd5=4NO*L6uuxB0Zv_7GEMx60QutMKf-?KLm(?c4Bgtw0!*o#xs|wDX>+!jmetDT zOb1z(HpLbjbpTJv2Ec9Cb)#z7E4~0H{z4iK= zls^8n%aIZx%@cw2nDYmbCsOg4oQgkE_^ly!G6KcZqHQUzk{JuHwU%G@5*kq-fBqnU%aAl!puQ7 zvn8e7(Z@gYHgt9QTPLcDksKbNR(iDft!2-@JSM0A-f;p&321l+J>4>Tsss1lj0ppj zc%p$PE0k1s7r08ifqB!>?Posyw-}BQrw!O8sE^+_1}EBKUdwBcV7PT6k`Lch46aAb zeVBf|P1{;8Ag?u$WMHI$m!48Xv{b807~* z3^YV?n1nR7Tr}I(`mfH!YYqx9;UWq9iqe6SAh)uL^mqW^RNlg5fs z*qT39#7%W#DQ&Tz}dez5I_dZb(Omj3hB0nD9 z82o%t@vL8oYYZ@-GjJ&T@IPQeF4Qus3-)JBImg%oWYp&@iPfcNkiw^ z-l{4}>-U1c;cfN0yBXIFl%tN|m(5p1qN0<{>&s72Q;F3}?T|TrN)1_$lYim0CCD9i z$x?tmenw#SVEovsblbTd_xn&?g7vRTVmGg69>St()o(uzrp)94DDmLXe$=nQBW1`N zfo%be;!pl=41a}R2E4V2z?jm<7Y(ClT^;UT6Rm8 z;+`MRT-B(Ebm;>Hs?P`UP^54?CXG|sp8QosHp8Rkm^V$m9{n8?uaqq_+Odko%A@i5 z1!B$A%R<@+A>pS7mdsTub)1B6v^bEEKKn=!53~r{<44ph(>_I5%vnma5ah{k@$dK) ztDaTNd%h4h+KU_hOpr{m=?$dEN-3G4TNH(ae?qvFE@rq=>*lSfuLXT>ZRuT2NQ}VF zCIyLSSPJW$z-pI=Wo4ma=X#HI zb*}4TWECgEJOVh|j9X=A(O5kBxGA1{+|IHT-1p7@f}dYzQSy<)#AdYzC*z(x+%R0U zq`LeN$Qv#dk;%X>8Sa0VPlPQ-GNm;M`B~%?C*a|`gjnFO0xc=d$$i9CxR%-Gl)2}$ znEUR8=70WoGDt#zdzd~n8~aqw36iIj#US+azrM e@P5enb^kuPa25YkPJR6S>d!AKqh}`m1NaXML33FE literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/GGT.bmp b/plugins/channelrx/demodadsb/airlinelogos/GGT.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b5c072fa8e3bf0d5a1581c06f97b0282fc4c89bd GIT binary patch literal 5176 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 N_fwze5AYA*e*p-qt``6R literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/GPX.bmp b/plugins/channelrx/demodadsb/airlinelogos/GPX.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4c664507700bbb920ea59aaca2a62b7e63f43a18 GIT binary patch literal 5176 zcmd5=_fu0@6ppJSU}1GE>+H_zwjXq6XLj6iTtuWvk#$Avt0=GtX%rJB(pw-vByxH1w!%y>bU>Io)C?05HxHUmigYDbMHOx-t(P%&UrW3UNSp~TKPK- z?QwW+z@r}8hB^W*3iSnaYIbOzl>um$mX|&X)e@o?+N$#(yZn$D;l`U94tG1v%8k+M z^-n9Sl&X(HPdjxs`WJtlxzFz+DkZ0(q&z1UZE2Dni=p5hFqS3*&le#hR!OVnQCWI-GV0uo-17Th&RLG@bA+M<1u#XG4)#$X!C@z`wVh z)zexolZrr=il)^bSwdiT^)5P_uGM|d|GkFB&HDJYr>z2g&e+G{5Z1<&boHmihgWdc zyFvE+ZCg&Ht5PY~ELQ*#%maHxzQdV)U%jOs$Xj0t!gH%v!Ngs zZ8J9bEEZ?asV`#XQJyuHG?iuK#rf10B-5k4CP(|?{as`dwFk4w*zR_gb_>0PRs6Lv zrVsxdG8$`T!l}*AA$#F$Of$mnVl7Qrx#UWE|MQ^7uOKq078%4iw7hk(~O1?5O)nL^0CGuAoPzhujtmXW-2HyIKm8 zf-)k}(-VWB$*#_=Eud<*&`UtAsjYRyX9(=tJTLPdVC6tZE!x5;E5ZY3y$4Ewh(Cq3 z+LaT7Q3vW$RllF-DgfQCQ2HoL4P9crBCXsay(lGp|#`?W2jOY;_ z74&HIIiuu&tHeLPjr1^UDoqFe2?Xbn{*LFZmGT9t#tV@1lDXNkw7}Agu&hW=7#wIX z?O|6Jrv*vH0{MbO$mb3|Z)8&a8%xt$Sh=9UOeC~aWHndNH9WJU(TydkmATQ-l}ZKa zLF!c601U$)>|@cxz0U6RwLj?ZbcF0}6@K@WpTi+vhXYvaJu#T`kkxn_)3AG|xMTeb zGI3E#a7A`h3h8PMBcUiI2wsQESCSG?oEkDV)YDp(55b=laIG?j%%DC9zH^e5pHM)1 zI6FNC3Wcd5bTYQ3JVP)u9_DUd#h_+J{Z;)mZUf}u6@&2y4&#Ge5b#jg!B9SLT)>+U z@wwCE126^1j`s3CyFCtPr&KP2S|6u|&l`h?P}i^(1^5bxW~ZbQA%sAGN8M0&D|n@k zQy1^!$eS1v%uX)IWneK>is4>1yn?6{k~uzid;mT)kP%zYUqeHuogC>YNehX?+Y>H+ zgR|a+u`&TZFS;6Z)HGdS!b~K7IHgc56w)5SNPTf?HFJYSZXMSc^8CR{I9rYNaIizY z?P;N|IGeqgb4CEX-TrX*(=lEaeix2FQJ@hoLy~_;6=bOV@DSaW$ME`u@2icyBjKRpLB`=_(K|ZG?qf)PYe2!`rvYcpA-K4K489b^2YhGUh{BMn;gmr zyXRwfpsAd$WjN5)1lghOenQwJ{_@vyHC`=#0HyrZJ1iq|z|yi7Iv#z|)f{r?7rgC$ z;Ou|lE28tU2axBsra&HRz5DTv6Hw2Fd)rAa-+P;HCtW)(lZkXz*xD}Yzwn3aS7ko6 zBr~EQIglQMr;%=vF}8k=hjBK0fIqZE=c5tsXE2t#)cJ3_Z%#0}wQN`KjzX4|TCASd zj4Z1VEi@x=s+n-fvw;jZ!Kp(Xgxzr9fOq8gs(%6itkmTF9S^tFGS*su3&%IezdSQM z%F{f~$1&d5DGp~(_Ogiawx;0hD0uso^WO{ZAYA&6bmhmun?EzCzBAn6EhM?l)+iP7 zQj2BPGT=3$#v2V($Qu>%H}W2^mQcXuG!)epCc!l>mx9j>b4w&TC-_~2;19fc0wN!- z!0|X+>DBhgZNT;Q;9r+V8R=|*pQ7qZ-v2nH^|B5A1NaZK C&i~Z_ literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/HGB.bmp b/plugins/channelrx/demodadsb/airlinelogos/HGB.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e87ad72e4d76460069f8fb0f9bcdb04b79f6b652 GIT binary patch literal 5176 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 literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/ITY.bmp b/plugins/channelrx/demodadsb/airlinelogos/ITY.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9c3b3b620191505abb479bd94233fcfccb70dbfe GIT binary patch literal 5176 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 apR$eO`}f(VJ^%KZ{Ga~ss;6@PMd%;;^_UL; literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/KRU.bmp b/plugins/channelrx/demodadsb/airlinelogos/KRU.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ed1122b76554c35e139d4bf9d4d12f5592bd6dcd GIT binary patch literal 5176 zcmd^@OH5;B6vyuvjV9{Og&KDzW_01kWa7dVCbBZKm`q%_(a0o4aUq}>qYK9b7+?wx znvj7JEG+}fgO*om=@k0pF=Zc|Eo~_m+Dk8e;lEtxPE!fd(&9|~(tG*7^PThc z{OGE3x&R;ZDyYEy)8@})GTH23!NGT@(`nWNR?c?VDYgUi0xNb3oxQNZ zulgZP?}Qdxt-rq$)^}x6d-)0{>=z&ZwY9a$iHT8>NGg>!Ha03|XIEEOb@z2mO-)Lr zQYMqlX|?fqT)-EMjg8%t$tp9!J#2MxPBh5oy#4$d$+!>c1A9*tE>G(ug~YnW|C_Y zAIE$ex9Fm^@9lIlo-NZ{p? zPB%C>2pzN83?YUprOIS9Zf|b~gF)oQ=H_N9m4Yp!50gxiq9W#y{+EFE$B>R|Xgx#k zdP)Ucuuk#(>_SK8HgW-w9*<{l?}&6g(u7?wv~-Phj9PEJfk$BKcp;$rj-4ubr+EJT z{e7dsfY25A1c}LH(m&86pOF-k6O)KDbg(b-v7v?)3T!cqZ_ImTUxb%_UTGwZt%Rxl zxdiF@yIQFv#q&!flA4+tWIOgYz?ia+Vva&sRaJ#NXIz|}nd!cM9SYbEn2p6^kw}Dj zYRHAHt*rtQxA44UsKWZ&Sz`-fXeR7}bB~Ue0@YFsi|4o6Y>`MVpYcJdM-9uNc6VDW z7C46TE)t45J3H}Qa8h81(%|>|t2rDzwfe8?Wz*A0c*)chP17t0D!l31i@?rB{wiT; zBD_%ftgS$eB-$U-DTwu-P?>=VzB-DmjKur?aD@gQ@E1 z&(F=dT&_?kB$Y_O+}GO+A=Ho#T8$PRl#ggM>ht-KEU1)_1e6U(`$zoEglo70^76G3 z@UzY#t4Wf?yA7C;6o@Lbw-IgVAo-aS4jrcQAukYr#+;e*-}^G3-*|iBg|GFy6n#+&@3 z?il}YQff6CRKdZUH=&k@m`v@@0^ZW~s{3~3y6B^A>z!lFPd-&H{(tV7-EJQn9mVMY zlWaC)?|aMC@qB{JRfwQD(Gl{VA6yWg{j|D&cK)t|k=uCRw x+VlGIWg=?k|G)Sj(q=aoTP$6#rD*b@q`ZG0m-w@kX*x>Ub3dF3$g6dsATY+dP2X(>>_1_H=d6bTS2#E7EER$>7$Vnq!>psZ=Y1QKaksvt{@ zVT&e!3TlW8LRZ?EdGk7Z+u1rZZ)Q5(JDpD7EFJvrT%0ZfhJToHx$|=Fx%ZuOzO&s| z7A?z+5d_9;JSX9|5;ZxApV1Q-e!qWE zxkKRTGrV3eoG`fX`+Dw`l-5?3l{Yq6_1aoF%d|E(*{mI$No&xX*IU(USK=rpYMAKIL2h@RDSEgldW7i0g(m90Ex86PqlSyVEV6BW zUmp`DPKlR{!Hkn6$4c;`Qsv6qVZs5>)zw`sE#4Q#SI32mr)Ego+Px6c>GaK*B8!U< zj~~NoG~L0d?A>jO97ZG;6*W+1!4WH#u;lO|%Yl3jmOx$cZO6HP?H$N%$_daxL&s*M>jF88q3r~Nxg~Rn4=ptLImXT zkqq#}hKZv_h~x@_A4n3S8KKY#Gd|d)1BTHt%<^Tm5c2k$waKvzz+|t{U^h5KqE5Ih zA&QwkS%zbn(=udOf>~4J%HL;(%uyo={TI2%a|Lr%8w{LY|{`F@^XQyxLr}Z@c6#vbe zZ82fw7+xGcL`YKxFJ8Uc5(E#z=kqUJtcD+91JM;C1cBw!EH!p_1#*hUANV7OisB>1 zCyv?PT1L#qu`5^lN$b7;EjCwGmCDg>{V3NkXQph|9{u_p-PFm|73FG*A3g?Pgfual z;G8g)O-qshz`osPDBiY}fC2yYB{d6PR)WCt@?}yE*{e119e`>3q%ruPY%%o3?{xa+ z%#g<;;gi{Qt2OBYTuNvTYs93T{owYy(d$0r(XLf#OgvYD$^khZ3BR)zDLnn?S<|amq(OKx$faj(SIv6k^ zg#|V^7apev2I3z|YX1B0n%mlag#}jh1=P#2LR(N;Km6dLk{O9fDzlo+jpe0sv$4Le zMyEG)%?ZRG^|SC5CEUa?PWTcglKAg3QE?}Z+kgjYhKYPDE_P7<0Q{WUT~uT{b+Q2! zi({i>nLWEr;Gi;jzGvY)B}xFD54y4zsyyBYe~(s84 z&!9u!`lJ2hTmxjHBc3?=aQv{?;q*ymTx*N1!D6u6Oj?azZ*a|=rhr+1M>XLq3D*f6 zkN&?mkHjBCtLsi1%_c=N$b$JVDS7w(HoJDE2AK?7=t}s4G$H984)ThJYpqsA2d)|8R^vtkqqi_()emygNL5lvCRmRVAvh>|5Ntx z5D^>%*oZuuLTtDwKAK@956S3go5a%kFE4Z8&Pz>V!67q|O!N*kPP|fE+dV#o zgL#s2{Q4JyW)XaE2J literal 5176 zcmc(j3s93+7JyT?yDbvQgOGQEB_dd$Y*_?EYYm`?PODh0V3lJ%u2G8i7~=zSKRv@H|w2Y8HN(pP%jjavB)Sww2GDr@9aBR?j_+6#K-u1IZE6}{PSD^}Ll!>|zrmoX ztu4>bzm}Br9|EZb8T37k#*T{ z4B-8vNS~S_+nU-_T%-?Yh()5wRe`)qf7dOxUqXOr;7k7Ug9$GXvOoCX(+wN$goJPd zSGHm?Y&=fHU?}h1wZ%ja1_US~BKj#5Rdfuerl!X2_73<$IdXUajpT1imJ)G7vt>4o zDSu_B^6FiO*?t4hkh8;01ZPLo}Kk zgHn))eS?EevDndgcdD{-j7sGP2KHoURd;o97ExN7t;7&vLVS1bkpZCGyio@Duap>R zWD%D$nVcw1S}$E}yo3PJz?b~u=Wv=1AHIqY>BQlrB$6^PPXrHyT)Qu|OrN{M6! zIIYvozVJdP8gmbW<*be1Ub%AJ>6~7GnVp+YWy%qV_U2|Q&?Lr7)6*1}OGch~x?@jf zFA*<%>kq0Wuoqv!r-m$i=htZZ3f?K9QYBQ1icT9Mlly=3Oz+#LjKD1ce>!sAV5h_( zlR4H#^gSEELu2n?f*a5n!S3C)@*csW>uR-w#j?6w-qgV3Pl-G2!^6(T#)O=6{vuDekPP5760xSIXZF9qIGmABz`Kq#}+7uVt)zUmJm)pRmSXnW4=)l15UhIyE z?kYT^xp8AG^<}x$I-B#xz?lNIPUn2@z2O}hifM-n{-{G1K90Z9s3|D8{@YmX_H@Ip zS4T5gkJ1H)s8iE)0f4?AYuAO!IVEh~`~MDi_kaNE9pH%CT# zj0O*8mEh390W3=J`<#I_tHpzZj_61Ul_ZK_bW-r5fdR*AYA4tcSxr`%Z2H3sI@C)3 z+}!*}#fGO4+=O^30>LdTP=kp8(ZH8{i_W9U226h>6u^ z>>RP#y{FycVlx6EP0#4RZ+gH?;h?aU1acJ$`|akJzmdziW1}7lL4*qAXJ_?-K&*YP z)8(H3_#?xMvEAF!dX60(1U=A5;!|&X2|+0?8X;i48^^e1mQE3$$Q#54@#Q_zv_7ZeGQl<;NSqV#`dl9g^LJ817GryANbVTdUsFe*PCB5}p`D|M8@%yxatoXHKiLUhg}0WN7!UULJ2sDzhJW zqnGo;BzOf1d}_$TcmC;VTj|wOCX*EzF%li64_~7t5Y#C207&wQ3Ea?7?ap1sP{uHA zwT2qnO{6suDOCircl>TuA$+pO&h<(;j}cmibhvc=n4{*O`tTQupLoR?CP3Z zkMjSIKz#fP(ZHAd<$t2f6BGA~ib|rQI?x!fC{#pZFAgsYLMy=1ICt*TG1Ibcbx-X1 ziAwm?ki{>;54_Z9`-?7JV{W+<#^6%v{59ciXT;mEwsE{wN_D_|h-M4|wc$ kt5C?Us=E34)$&`lwNfeX!K0gxKeRu!g-;DxfPVo03r$5GuK)l5 diff --git a/plugins/channelrx/demodadsb/airlinelogos/NAC.bmp b/plugins/channelrx/demodadsb/airlinelogos/NAC.bmp index 2b8ba779a13953639439c57c11b6df6541f81409..6b46b077963c2c5c540b45c7110ab583c890e54e 100644 GIT binary patch literal 5176 zcmds5drX_x75~V#R7urW+HGyOwOJWk7HO?oX&bcNLrGP&Rj0MlvSpbnO{>;ctF$Ro zyGWBVt*^CJR+fY$goF^x%V1-$G5Cdz4K_A@g25PrAHe~GjUO0{ZTvm=`#!f(SM`so zb2Mom-*>t9+;h%7zjMz$=fZ)X)!s!2&kxY`TPpTsBMoSPoFxYc*`4b3exc{Rk z7K^Q}CIEuZup&s(hnES(xN^<=Zl3^;?1_Wt(=_2*TZmiW@*xJk*fYeu6) zA~`P~YA=#$ipi;s%{ekCSiCKlcWvaZxh7S^8Zp*ejCf|eqrrKHT-vNvw;A;kj-Gfa7(>W|R2}pxUkKF3}m9j(1DyC7t!#h2?A_Eun>tPN?Cgj}btRMXxh!2% z&cRY?P1Ih$yy~8Gb&Z>vJubD~rh!7>XQw85rza)pm6@TArZHVhG_2ApE+khbF>N(= zPdgMteP@%)KKQ=7v!2`zaa?+^w>}x2)D4Ixtb;~_44jyyS%fj0N=-Fie9h~UUpo8O z(7ZVq7#$z!n)eMmt^JEZi+!|vYa{3|_l}#|2BZztMoO!GpAY#$Y*>5B?-?}@w?bEb zGbryl?Q3A5;pRxl4!YYhGN|AgC`1m2h@@gmGfuP2sBE+Y^R(7t<&Ck~`tS~_ zn$v0Dj8nQ4G-6|xmRxq5bXZw$(Kk(b)Go&`IC=bjmwaOMf?C>;Sy`AcwM9dNON%a9 zcf*)bCYPSwE?kxOoaq+TFU+~U9{qr98PYH5DQVCd=Wtj}Z?OeSe0WEtpsSK9T@L}D%+bdH&%YFR^gR_AuBuH)yX zoCE)O#k9waw1(As1f>&dyki`84vv=H|*;d@-?d6=xXqz>G!QT3=ibN9JrC zTPSQL0yEB~r3i8i!yw;qe&1+A!*P=dhGsL#t1MOE*!*TT7F+UNyXK|I^>EM=4%=CF zJr-HK)P5o~@5|?s^AQ6_lBFVo-x*s9V6E*!5_u;Qa%a<5`Ao*L*;JzW+{vq9_f|1E z8L-VRIJdS^^M1!-aFWl$g%nl^g{C$(Rv{i*n1tY>e}RBSp*+iRh+fX=REMHwH!Mm7&k9TN3kHLc zq9)Aasl;l0EwHw}2%@$dg8~cFzy}J3C8(fDz6UlG zN#1;lqIktclEk|3G+d4sbrxdK$ge|z4NbmKzz*|f3kI_MlJEot8#o$DNCvpDRlF^{ zTX^tAny>Q$0lT#&z@l;fEBx54w(nP0KU7oGap_`N^>(3n_@@Wzs;eKXuKvw|gM|X@ z<{UQLvvqYxYHOdWt2=(|7;iYtWf@tw_=V@6JFsux<9qkk?%n%j-J`i|w!$WUOkIWX z!`mDA{1f-@-9r#{-}+|0fU5{M@1J{s_~JbT@il_Dl_1nA6^LZ1^z*;L-@nwSeb`?=W5O-AVXuHt#F@r1ItuTIm6FKhe$&6YF z+_Ar^YA-?DNf5t%`YC~nyKwF-&>sBGzG9J&2%E)x2SMCR5YImRh{bFUheDBXI1~)V zmX|+DM`gK6wiU)-HZ2;7eD}6n;euZrJOIj@e|dcuLHx4zhc6!bIfykk?Tmzipl3EW zYIf~DdE!J_>JLYbe3c;XsUoa)Ynk$i7G9{hBW?(O*!}9!Utu#J*ts(p3cm8|BfAOW z)kDvZne_Z$U#vuwoqp@Bg@t+aa?jrR+u{qKMN(~+m21pebMy$pMwtE~h6AKianb_H*D7EYYMIcf0N77aaij2KsUtu6F+$+s+i!pH)?0v0eDN}fofj{Gh*Kc% z!R?5D01~A+K zdab9eRn*!#?VZMc;wsnQ(b3a-#h}xc#gp;4S*MkDwDq*MN<{oC6^S~pv`$#YKcWA> SAKqB}pT$1px&PsVu=+Qjn@^7b literal 5176 zcmdT|`%l|d6i4Hq;1B-bGub94V5ZyH%bAT#gQ9yW)9K7~3+WscrjppkfRGr#1Y{P5 zLI5EJA}Qfj6v{)Obfru{P)ZR(7>^;<_4{bc`uNFD`F7vOO&|ERKg^rkn{)3y_uTV2 z=iGDex5=*`csOpWB%zJRFAcxI&;xOgppA=r5S^BXxZlWYhtZ8lqTbMxBTT2D{U;^JaWP0iBM658zS?AF#+tyXI=7-nW>^78VQmzNtG z8%s+|S(Ysg(%gXJ?z5npRg=Yin!GW^-FxTTxL_dwV9t3BB!hJK$wyWp#CRK_}=@QBg58G^A3g zIy*bnYPCY4(CKu*gK=n|k&#hQP+&5dU@T}1Ik~yHqobq1pP!!(Atfax^Yil!4GkL` z8&gwLur+XYcXz`s9UUDo1o#&g7Qm2`le4n2VzpYKfDG_hA`?H9#$vc}WMl;T!BG+yKtLlARwb0D}`48o4Ry}cYK z0tX|AFKmZ!o1UJ=2&5q#usf7N&_RNXA``!io$k*iGVwEvpK=7NlMO=idj0FS{f;}r z6wkvEV2D~=uCU7qY3#jyqsolHAQOMu31cDdp+N&8(ZUc|UUw+M<^enYEF)&3` zaGp+OZjME=0Zsc)qy!}s%ZVUhE@LxPH!JngYo_URdyCSH5 z_7rntgtWomfB6pWiL@$$z?&9QT6E}J95Kdk9P)^@-1WF)=VQSz5s!n$_|+@UUnd2< z%fAWX{9}jc^!M2hFR_>JRnQ-tXA^fxEY+ml+$LaxEtdEZ)$qI+=VzZdpMD}VevS>Z z0Au*+uG{TjzU5VY>WqI<;0JP=4jtKMlf=;Vwf6!3R^6r;{H6EU(Hjyi#j^yRa*V#N zanJwZogDWRed&5}f8cy|ciko2CGO(bb3viF$PNz*aU|x6O2^FqPNzTlu#glIc2c*N zyf~HwPOh7JoUYKg(=V`CA`TEZ|D89PYsGFP(UPxRv(`wLMO19tVTc+2hI)zf)!Bhd zkw^!;Eq2FKf361t8@D|`!VvrvPrQ7T{{6TA1AYV{!0byD5)$CS`4R8~BxfM-AaIc6 zc-Ug%=l)3XkG223#K8Yb1^dP4F0tMST~4!b{s%K20t@p28)?1{k@h)hSRM``Mfs2~ z__}^ObeaseoF9(?{=<7IoOT{Rx{f zT~{MHZWF(RwG34>siUk1h*G9na*q&q(geE9vCLj-zq*B!l-7 zU*9^-q`o9MFL-6l*<@yl7~@A`-xT1J`49MQRxi{gOvZI_=h^MPlPMC5gybX!afu+0 z$}2MQhs#)oZb`<%wJg@Pr8!_5I9WW%)7tL?vnHeG;Pb+1;%CDVxITZ>OE&#ihLDN> z)T_*%1d6D5t`U3Vl_uuVw+9r(t%k1y@i=Ha9PtF?%Ib=*^12(>$}7n;XMKY;%L6qu@$ diff --git a/plugins/channelrx/demodadsb/airlinelogos/NDA.bmp b/plugins/channelrx/demodadsb/airlinelogos/NDA.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c7fde26344c00b6829ad5cbaccd0248b459fe4b7 GIT binary patch literal 5176 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 I{5Rl#0KW;poB#j- diff --git a/plugins/channelrx/demodadsb/airlinelogos/NVROLD.bmp b/plugins/channelrx/demodadsb/airlinelogos/NVROLD.bmp new file mode 100644 index 0000000000000000000000000000000000000000..41d25dcf7d19598c040940a79f202a96691cc1ad GIT binary patch literal 5176 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 I{5Rl#0KW;poB#j- literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/OCN.bmp b/plugins/channelrx/demodadsb/airlinelogos/OCN.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1273ab305d0bc97da42f8b3b08f7fedd9075d8b0 GIT binary patch literal 5176 zcmc&&c~I2X9p4_)PNtLpYLdppnkF@==4frArp7qcX^n~23owaMOqw83gGWV;H6e(K z1_ebFL~f8Eav#g?!m^ypv9PeqCGgvez1Us$K7V`s=x3p`or&pGti!&Uee>S;ectzd zKi}iMAFSKF>X)>cwgUZ2_=V!<7yXF#6nYx%$C#A-boMtRKsOzv=FoD~-MbaszfFyt z)d-InMX6R*rK)=mX(O!4GG#}Yy!|~j?_-Cq4F)=NEf@o=?u~F7c#x3RagE>zBtV*^ zIX@$?{W<+;!fcQMQ*gH;+LDGpBGgj$3hls`q)jBM zdmaw5X;>CznSLx0hbp++rHw0n9t-7jIgNbE=MEBo`5mJANvpaB1iWser2bV+f7A^B zUpuC_2$zVySjv7w-Sc<5mSYs(1b@;x3NRXscIdf8%|fKKe@gjeO>fKFH=AU6NFS@J zYLXu*nEDmis-*V`Y1a?!514;e8c%t@Mjo_$? z7Y?D9G|u96!?9qlXy5Fz4C8VkY8N7*R9(Boj2EYdho`7orMi_NN-%vi%B*_E@5>&gQW4lew zm`S3;VC8WrC9GFfyge3WIfP>7?@$OxC7;Kt=-44`d{e|&g6R+Qr)I_fs}H~ega5YU zc0A|c>eT(KZe)JN^0>VL7&T3y@^O>7OhQS+AJn~{dPzN!9NeJOzhvkptwaD%TJGU` zC#_=viQ6uNvz#V@e~Z^iT1KD&tI+JWOYx3i>~Sig$7LR%C=aIC;&H0b2Q<@sUdm~A zJFKL`;&QwEAcu`K>+N2T&rN#VE-&fw1V|b*HmlJwbH+3P9@5VT7zzzfj;ew|P8)e?U-=hrrG38gdSzNCB)PHdueTT2Ew1Rl zX3{hLZ}Qn)Ma<@9cD*dzzqG9Jc7f2v0sSs?*4fDTk_${UyVsvq!DDc{!r&QbbuyXaQ^j6A;i( zS~$hRT`we}&vwGmKtgl(} zQQiBCFJiAzV;%0CfIAMZPMc?{KX@E%piTPza~B&5`f7G7)=nkM4_TIhp zS$Wd_irAh0XQr)k=;LKc7!X2r_|n9#y3vT`*P=IM?Ot;E==uzh)GEx!-^nVw#yzz; zw=}sO$jFs9DpNZF?xg!;dtlY|`hvcc!_{ycbaHD(APjn=4RU1&W7Jz|kt?plrt3#* zPjAbISur66=l2v}IZ(NEL0rLk4!cnB;qwU~kb124$ogBU$LL>f%3q)i2hh z)n@Qe2*ru5C*I9IvhG%6kzo5%=h~}=PjAipChRs`5Vk13=2ka~D`|fv+$|l^2Aw<% zpb1(eyMCKs)Y@=Y;TCHy8DQk}Vu6{*XMfkPUYvQFiJNbvTaKKH z``|m=hyngeLeDPd5Anoq9~ltN&wwUulWtiMcjV9MNXzV)`v2!t+f?Z27(yOSb$x`P+j<#W~D_D|5H~BqMHPgOV@;Fb~Fjpa1=a&Pnp%7CTJCLyV1s z^&1;2D`K`V!yd~$xwf(*tM$yDybV7)6Y=t`@jmsOj(#}sBj!H`BPhx`#Ut9o2RJ)> zyKkqTrH3p?+Wl;L)7>FHXS}0!L^JX452QKhoI5mV{AV-8?bIlSlSEySMokqlAa5!W g;(K)NEFOMG(D(;T#vkxbi-@$#0+RV0;6H%>0)JZ5ZvX%Q literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/PXT.bmp b/plugins/channelrx/demodadsb/airlinelogos/PXT.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0a390b09479df2007427730cc1da52c2bc200d3d GIT binary patch literal 5176 zcmds52~g8#7RT;(bz664m)4d#vs-2zORO$X5Z7g^TtTFf!*W#Iy@wvp88M6=%wQq&xqN5Jq^tIZ1TOx zFhX>6l%KD6Y)mvR2$S?(JcW`+&dSJ4O>SvvW_3U7>3#;K>;Znu!|LeG-R>0?VcK(>1krsM0*xK@T#8$ zM-7k$Aq0F|TgwaG?md2pgAn9T2*Fb*_gTHHrKRN;cKqK91-$XBgs4Y3={va^9vsNa z%dxp+`A6js6@T~Jk3UBE`uVW?dNZ*8g%FxU0bIbKsj;d4f@ zW;$qNZ7%~2Ml}t3jC3?-cX!CTURqpa(CL;|76NCD=&7 zY;*`zz-$noJ2v}sOnlDB^7106rUd*I;1(CAg@XC{xrMpenQ0-&C2Onmvop{;@I=3F zLLE#w!$U4=?-isaRu+=S$41s965q3kw5Z?>|1ySIU#F?54yT*4vT{!k3xx9EFGz|C zvp6#&o{o04ClS1#wm!ikPtd7_w_R)!-LJ&?UTbZt3o_Q|X=^Mcr~2t4xT8ayk)Z%x z#Nz_;U>_^O!8F0$K0oP}EGEbc(e+A{^XEk0uSG(^x7TbEJ?x^sG_QS34ZUnc%S~ri zl?RoVbalYP%Bw=*6uEw5nC9c!tpMw@DtWPAsznV-+<41(uPM^lgp zcsyEO`fX=(;90FqoDo7O6k;xD`m6tDfZaRzoQ*U2Bs<)%jZT~7@dB@yM4>%k3l#Es z0osSVI$H1Cuuj3b!PF3or@=!-c1kcxee)6nArPECpJ+&z0Llaf#`56LON>mk`!vBx zueR`B&yTI~4pOLt&wGhZ=d%gdiB~U_7v@ExRGxRX6ldOvFg}{>c8Qvwfk!ISALX{z zP-7gB85pN@oHSWL1HGMhTrTE@xy3pfPK*wxdtJ^8^GI|u{2^1CrlQo?yROn{CE$+5 ze2Gf;vyaDl6YM{WF#A*J`J-XiY#_4)r1HbeY}As!F-Zw_k3)SJq4kS6 zvya;AtEAnmQ*$#@V;#J)@wvIVIgrVNe{y_me7IjYJ_7AmC94}d8EkKD^m0(a201a* z4-0z^c0cYAe`EkQ$jPxG*c73OV4Tz4R4ZBE;bh~pxH#9&pz%is*MnT^?`WJ}cP^_| zR8Z^d=)i+F_S2?mk#LebBH|8%=P5o9?qOkJq4Qa1X&KeW z$IH+Nc?^Mg`_~5!y`xAjHHb4L5Gf3dZ-VXWtIbF0^b-vFr( zEAa3KhjsLH;8+gA1sWL{8W`$pojQ5w(7T6~-an?I0v9-RU;vRA54Yga(GlLn_~y8` z@Q_MK+~50p%czesGf4sdzP2{jUszjud3%K3458Q7Zn58}z8?H=GeaCxffQ^Z14Dzx z=0*-@OctL=AP@>B0X%%$3=aOph7So=cY9lFJ|(Z9fKpJ9A5Or>$Hx#8VsAJ*gc0z# z0H3(%NVs=aRX-jc9)erI2F{(B*Mq;Vj$vwM^2WY>TktC?Dq^u1*}7mdYJEK2Flc}2 zgYkzUjfe=#B4=h~kP;IU?%qwJGiqw-HSj&e=S}d&IkL;uPB?dxzf$~F)s^w_v4+M* znkO~f++EAdsK|3j#5x^0azvJklUkZE>^p_K=kiyI-^s~QNl6Kf_In|W^0HC~hby|e zXF%J>?wc6jZNb0LgB-$Fihq~*VD`e2c6N3;_|{uUL;VY;7vPu1F7|t+`d`66$>-zn ZSTAqS#Dv)X{^xrI@89~_5x;`MKLKG52t5D* literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/RBS.bmp b/plugins/channelrx/demodadsb/airlinelogos/RBS.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0b0fc608a342aa819ed43d54e144915a24ee0f5f GIT binary patch literal 5176 zcmd^DYfO_@7_KJEjETRtAIp*@CX2=`yTmM;Y?>|GlKmQ)8Z~awm~1Zlv1MKs5EY0S zyJ?gPVh|8CUVuUbI$vo z=RME+zNdUqS@9}mp?!q+4m=0(6h3XByoNW0vJsuF?-ieg4|vU&-}3qSJf7#Gtp$G~ zmc`$50e^li_`S|V$d`I?@!O11hb8vn;x}m`iYfnU@Mkmmcr=5VnM^JcN*9;J!kJud zF?}Qx*<7|D2RuuJLU5&$xqNOOGmA^0C%PbKvw2bvhA`prM3heE^op?0l`O7W&ASZ# zdmYK3H{~?Pb+aK}pCca4V$;}Y2{YJGSA))|4d1z_*F6jsXLeJK!AIdU!FI!&{66Oc zwu{u$`G<~6Bjf^K%UMnFV=9sBY|!gf;k%a%YH46;W`ho{A-e*)lQ-aKsnOW=tEFcd z_y=0eHT$J9p4Y66FuSY(Pd%xUa=oParwS5|=kiGKd^H_D!{uVQK++3yhIuhiD{!i#>G&;<2a#TF*jz<=Wt(F8iy#&0V zf5Z-#B~BP(Ad6(w1I8&Qmri@I&El~ynoGrVocly7k)2?aysAfbyxas0A3ZpuLq4qj0t<_|ii-NbKJ;e1o?LdbG)I}ttJs5UT zYg7hR7%r3Xz1&`c(?i(wQFIN;$d&4XHj6IW*J8$UDEa4vLN4@i`y4H`+E^q5I<(Yj zl#&3_6HaSIzn6g@y28P9Qg{QcHt41mLMZBEN7 zDC{!6Pdyz(HS!SguU;7uv)zrqDy#PuF#NDf)OKDAK_d^K_yhluodWi4+xHbBWPb3! z@(s?7TCH4IC@ZKM?^Ecl=QPEOKrEC2exv={Qf@zS{k#S?ir1TE)5xyRnfQ1k6DM}*XT|YP zL}16^x5pb#C?QO7JUC2$WL+tt{A9tL<$vVcJNy z4L+Tdhd$oGUJHJoD-rT9 Z{ajn7aeZ~yg1>;UWZGLtF2H{P{{v>ft!)4R literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/RUK.bmp b/plugins/channelrx/demodadsb/airlinelogos/RUK.bmp index af458dfb0476fd9a71bff41959b04234dcf75b30..998302750e50a765f28acd85fa0c5776409f4c70 100644 GIT binary patch literal 5176 zcmds5X;f2L5@zPi{~3=3>-np;pyH)koty}kjt&`a@ zxlb1bPhI@n@tYO>MNS@1Ik~^$CHrs0?~?$Jj|+Ge-+G-O?KtisK0(u#=q$+;1~4pT z@uG*)^-Cg+m)!8%{;=?IdfGtd#kvIxYC-uY+Ns=2jQqKS&#Q9J`wAj?3JvQh; zp}?i|)}74jeaDX6lvrEma<(l_{%80ZaXy!_lgn@CjGTxbNV(9VEB~D1*?jNr@Y%%S zlM%0y#hHoRYd@wvT%7z(jk=BXWrnIv21?Hjm20(E)~Wsdna0u=`bzc2s?~Z5HLEq> znizKT0|pl-|7%=sMsVQugnO5-j5gE{K7P=kuUI1$H)N+aWZjr-tnDp2eJa_TU2-{P zaqQyF1S(>n3OvSG5h}6o03qKvdcWlnR3y?;YxT$(uLu=+Tq2?f5BM&c}EL+{{8u| z77Qtu#C8|j>k3)ADPm93Ygu7dh=T!yaR=;&`g=(^27`S)(w#JsqfwBZ=99a5glc?r zB>vz=VoHkWcRPf(_;OqzLqp_X7`LA}F*bHPQG&TbmiD9KoAWKFg?R~CI-$-cN1Y6Z z`()J*iUS$ycnxOh)|TCyj~p8wlJ2659gPGG^XV08NcY zS8J^L@+cnY?GAG_<=SZan#)(*$(ghK@t4eGAIb_oLx*px+1^kyGxL$SM+V+UxSMfo zG?ZIwfGF};~uuL2c2T}Z;C(ccH)3jpq(z?Ry$&w1u(#8N`w3@l{qxk z^11XqEy)Y8QsUWa1#Zxvz3p^*J6;1>R*>#zE+5D;2zD@v_k=0OS({#4!?&9AnL2C> zg~FucfOWPs3hnifJD!bd-J@TLkZvY~u+0@fB#FNdlChzIxcznkRx03iGa;0~;Q5(9 z&qnjKw|hfXd7|%jrR+JP)g60q2_sBwB*20-TRq0{g5A#(eKb-S3R|wpohcqYg zcPI0A$L_Nauv8ARH-y)_X=e%W7yLV#>JUBB5$Z-c>bzE9r$_Ri7#of9u;J1*kke3C z(`3P3*gUp_#exZ67T2zFTA^`-^# zoP;o>3B?lTMj`tM$-nY${^-y^%pN;`D^-80LTO&wi9IwPU5n%o3%}jEh7th($nBP6 zBeUn?#lVB8RxEzrnQ*+~`U-!fKG06j$8?$3nk9bbE3uodOZ@8Q_6X*F<`42%)m!nx zf<$q43@>sA?FeN#&qlrA{4wl0@~XI#&88|NnlQKZBFAqrKJC2~&5s29oO;U7ToIfL zlcKSK!?&1%JQlzBY66KN_+t$#e#}ih`aPJisfxGHgaHt_)r4oOJ)b{}AN!8VrE9XO zO65ga13fY!OAnafje5NuZG_FQ@n;zb?e%kGdHH9=Ik9}{o(*VH$aQL{H;N0>=jxxX zA>G3yLmcewj@h$;YpvmDw!E?OKZLxkzFN3J8@rT4TUGz)*A&tBhzZeWMsvuCSmaP= zW2E`iVb_W~H?ZHZQN^2$5jTk;_zPJEs7yXX3)?NxXWP`|)b!M3#FjN*@W-tCS(mYN zD7qBUzwTuuAz5&mb26AT_!a(vcKYb{Q0N_R7+ z=S+T>m^gLV1*Pa?y0rR!A;hR{>2Bty!c)wQ=0Vcc+9Y-|#x7u6th}Ffac=5ItUS7a zaHCP=cQkZ9EIuTp76XER5X%5{glvi&SIgcsLq0h%_J{mOhX--I!BL2lNw_-|Q-WB! zvbGk|=KtkCHuC!)ROyjyWcZ(f@j&Ak!BPm}mY?PQ{F zp;Y1yIu5_@11>ex%h&81jJMsy$w2Ynu`4u=T&5dr=Zw{N+0Edf)T=>LR4JkdLm(@&?PHriNrtdLY;0RG4b zd~vN;k^Mh6KG@G}CAZGUri!>*YO2~AYWlm{KTM1hKBlLq-qbw@rn$QEUCU>NqS9(c$Ljvo>3*E5|>z8A47xyWhShJhr^3oSK{@RWmcwaE&Q2NO~u=U2QFx r1uYpmse+5fr{xWmrMSu3?CE$z#4yL}3BJnkbu&Kpd$)!K{0H#Aaf)Y~ literal 5176 zcmeHK2UiqV6yD_I7pPG%A{w!v#-mb|qM#Hj(GwF*6p2O?6p*&`8lxg2ML8hGD1sDa z0VzrcMT$rfQ2{}b&eC^*U3O;+`DPzyT-z_eIm4XU`@VbM{cd}M=`Q^_EXAdZ=L-Do z!yhgBilu@li}f{raK0gb3IQI}%)Y+xpW*qJ%jHuu^^(bCtPi+L{%MZ3_d# z%Wz*8ZK2?9V@0uWoDbuGwboTImKZwgx2heySIqEAU^Vh)*L(Cc`+{5%E&l>J3F1Z zSjvtL8t(0M*|hki_P0?E2M9(cmB#wo+Uu$~Y?yy$zp-2&K<+ zR^eklt;t;cp?-fW9XHcu-rLuVaJx|g5r6G*HeTdtxR5c*fUmk9cG>j3li|Y0*~vsG zo)n%xWX3kp@GxJQ6&+NRa0PeHf1zI6esJ5e%+E?2P7L*QAjHl_i~eQX5Uu>!2uFhj z5VB2|1|K$`lFJ9X+r77~fg1>YVSHp!LUd7LbXL?km}Q$RJ@=cbgc76Husik&J-UPN zPmc(2GE#RkRLhJy3(FN53D^aIz`gp|6gBdWe>qQb;Q2%)Pja(YtXu)p{I}5jQTCjR z-i{j=xNg?C;r%B=n|Zm)wxRhOs8#237-4bZ6{vWcuf&qumgQ{IWiG~x;Ws?Xz7hl& zx4l)F|I3O(ghmlEO~PLy76FzK`Hz#Kx`&x2P11BJZd8q@#Y%*`GAjvyrm6>@YdwAv-~bfS5rbWCU)7X(S)xER&K}q#oEU?hPxCia zhv!Hh0_tS25TOsYHgBvfL5ofE&mN>yAB|=XQm+KkB(6A_EB?D}a#A)u1sVR>8?532 z>|$78R`-|GkCw~Hr;SVr64iZNOo0nFmWU#R38$Ul4Tz!Au6Z2A65bzY-zIpv1ojz#A;wkMvE3*T-(BmN zGlKB8wTN=7KvQeGmLW*goqitZL&>k*+H+**Y^9EMX<)BF|v-_}q)Havhj z#9YPRsM4rY^u#Vrxq*m6a{ka(%%OqKHZZ|?fx<)Ak&P82P0ig*Q^8RE_IY8Rv3SM2>-7}+Ii5y)^7;=DyYBU-3lcQfotj~|?8isW11 zEPPo}X3&>L&7r>zM?C5KI1#d9$?e$bp zAR+<%m4QT|&u!Pw!t9_F^N(2WX>Ei92t7;%?9rXzj}SSYFUt#Yh}!GULurute<#?} zcHJzxWi~HC;ka#Gjx&`W#ulscZbV3>5_EfiArpF~B!31V#{>@9s7$?LFA0dn@kQd#G z0ysH{{jB63k=GSwqUTdWyvx($-yty|hx*ea0F@uU{qG<3h5yVhfEk~E7VCfL8EEDJ diff --git a/plugins/channelrx/demodadsb/airlinelogos/RYR.bmp b/plugins/channelrx/demodadsb/airlinelogos/RYR.bmp index 108a324a7deb09c083add1fdb2cbe90fefbdb1d0..549c95603f0a8011cbe769ca9fc5b2ac6860b249 100644 GIT binary patch literal 5176 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 N|IV*q)b}qM?f(>M_~`%u literal 5176 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 diff --git a/plugins/channelrx/demodadsb/airlinelogos/RYS.bmp b/plugins/channelrx/demodadsb/airlinelogos/RYS.bmp new file mode 100644 index 0000000000000000000000000000000000000000..126ab2073c1dde7e2e1f415d24cb9f7e25051729 GIT binary patch literal 5176 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 AUjP6A literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/SKYPARK.bmp b/plugins/channelrx/demodadsb/airlinelogos/SKYPARK.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e0fbea8d7114257b54afe021f588bcc83456f0fa GIT binary patch literal 5176 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 literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/TMT.bmp b/plugins/channelrx/demodadsb/airlinelogos/TMT.bmp new file mode 100644 index 0000000000000000000000000000000000000000..79704919fdb6aef2c01a719a3c1c4d033e3e483d GIT binary patch literal 5176 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 literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/airlinelogos/VEC.bmp b/plugins/channelrx/demodadsb/airlinelogos/VEC.bmp index 7f1e528a3a1258e8e798afbb2fad33df3aa08e4b..92727ae0c247995a926924848fd883e346f43f32 100644 GIT binary patch literal 5176 zcmeHLdrVVT82?%*v+^pJmcF5nTc`{lo5qlty_7w`vFMh~KU|DUV9vRS*?jOS1ty@& zW?*U@TZX!6wk6JtEkV@9C5vWm45g(!`cMRX3|c{CkQGbszS{$Z2`P~M(ftAW-J5fN z=Xbw*e&>AOISs2bQ-$FBTZwl)Ua#TBQXG)r9e|4ur$Wi)BiP#?-v0wqVogE8y#M+2 zpU?mQyahCR0dd6#Z1{5unXA)biZUq0j~@kX^?fSe6;pI~Dg?!S5r^-GTzCLh1}sc? z^0DaEqb#xE4bbA+a|}*v6}KLkAO={ik0{ddFU5!n8p)WFG`Zx}-EM zIyYTX5?Drh)1{?pg4`Fy#Tl}_f%PEnV1!$HaX^cpWirTIB!dMTOQ1>lbSJKAbZI}@ zMlzXWK{Gftyfbd-W+WSLr*O@LM`H;qJ2)*~YNr!5ghV~T3qRaXP#y%>? z8M~c@D640|$zgCXQ5F5dw|c1^E-J?*e7iUN&|t`K4{#Q!oi3F5c&BJ<&m-Ucjk%2x zgj;-K)bDV`<~RjKeS(sHfuWBeChsosZ_q*j6sVzMdE5`B@0TxE zl_j-yT5i*cte6N|m0hc5Wdu5z6^ox^@g}5p&}thYX^l<1@iyFGz|OFH3Zi|i{sWjN zUFc+&2);MIce-HP?l{PkPh%`k3A;sbJZs(g%CbB;H$Q$F%|jmoag&$b#%?hSkN%~2 zsY{;OEz7*A$mkMh-@);58$BAmgQPLmNRpr}?2McL)lhN>TNi9@`>=@9qF>O8cR$Hi zhtwK+`9Z{?0h05m^i8gr+U;Wf`_BkpervDOn>ai`c*ZX))uNcxpFAP z71jVY3gY4O4bRqW$~dql`S|9w20ElrGYkKctD|vm-ch{JDShRZbo~TmFW;1Bbjx17 zsY!I;&`D`vf{3>DKo3Lha{0Fm?A3{_{4a-iKaa@MyZv>94aMqC=ww9MJ$@3!dVVX4 z*_CgYI4P$!JeAB>z#a*Flk>*uJ?|Kk7M`yvt4vENUm^YJ;J%7wqLW)T)Eaa0m5?i& z**OUgVjCma+rI=%xErCpslcI=1!NnX=EzS5z=p@6SFxs()C=}vL-BkUmPW`$4_1Mn z$CyGqJKDSnD?0onHt2XO@4^V1cjH-5s({(UCUhf4ezz|Dte% z5Q;=|h=X4QvDu4xjyoAm+cdNz0921($4wDT?AeY#2SU$}s8(M0zlB8}d0+s#u#Sc_ ziFOT*aA;|}TJH#}bBEQt)l0A8BZ;q5TZP-57=#Vwn*zs|HL5_%()0k^3Sh7 H{sZtIaJEmx literal 5176 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 K|KAV%2k>8Ov(Op< diff --git a/plugins/channelrx/demodadsb/airlinelogos/WDY.bmp b/plugins/channelrx/demodadsb/airlinelogos/WDY.bmp new file mode 100644 index 0000000000000000000000000000000000000000..40f37472ae358f339a35f42f56364d9e28990812 GIT binary patch literal 5176 zcmc(j`A-u;6vxrT|G*#o6O2ZUniy{b;S8XOf&@j72pTosAczJL18BHGK+b~54Fb|C z7D2g!6bck62r3}u6bh81g;Ey3FlIvNZ=}<0b~iI`=Xjqt^WMCznf>AICTqV#c<#jQ zh} zV939$)77Mehgs~>ztY@oWukndG{-IX)QDlD(Vy}md8=k-dQLg68XLx?(=NhTqum`a z#PqPDv$AY*uzz-9Y-W5EZRV$xo5rRc8S-NR6P-=V!=5x`C14F}QX>j{Jl5NyBKjE! zsVck_Sn*GfD8RhJaT};QD}|9Z`=}LK-)C=VVB{(*{zdg1NU){FQ2|AM*GdELbcjm` zTT_96@@HOm;Ffhnjs~I-@4`o(A71))d@451)?mdCq_(o$2%Eh?jXQTV+0_ySVUQPs z!qm_}g!LX`g4fQb;9Oo>Dh;?zBq?sz;a00}bMLznBNFQ{da~l5RP;sJ?gs{Zeqn9~ zL9Vy4THs+%VjFdV#0zEsYc5PD@bww7sD2FfLp9Ff7&~bHt!6P)YsttV&US-AKTAEGxarhCXM}D-|rbc25!2j2+ zzqxKnoA2$8#t0VUeLbYH^xd28>T-kA>JP|@U#n54d!7Lmd>-ivb~2U})y4T)WQ3G| z)&DsTxm}p$ZoDlIdkk~H3s5ff_0U(>;1X8+P!ybmIokeUl8bq?-GMqm4CGjU;E@YK zj+}FS&GqDrNN_rZmN+u{rS%4<)gO={KPJO&AMTPN)%}_j+EZ6CKRE$!M<$D)2#a9b zBl4?NQ$#+{)`-*qr)ICDW={E6Uso0qw)|9M9BBw|SaYl`VqVTY7exE`^CxodUPO*e z+#$i~WW(G4!Gd;VT`&?qFa|qXDq;dtFWb<~PYanh9PxFa{PUYNt^WAN<0o_DYxh^f z7bL}q_Hc5X2nv}*UoE3ajLlEM5a&c84{4RJ0zdpn_~HD*U@yL~>Ad{#<8uHxpXh}T X)q}4BKm4G@p@=UczOd=M_y_PG7sGQe literal 0 HcmV?d00001 diff --git a/plugins/channelrx/demodadsb/map/map.qml b/plugins/channelrx/demodadsb/map/map.qml index d18c00ba7..b4e3459d8 100644 --- a/plugins/channelrx/demodadsb/map/map.qml +++ b/plugins/channelrx/demodadsb/map/map.qml @@ -1,5 +1,6 @@ import QtQuick 2.12 import QtQuick.Window 2.12 +import QtQuick.Controls 2.12 import QtLocation 5.12 import QtPositioning 5.12 import QtGraphicalEffects 1.12 @@ -246,8 +247,13 @@ Item { visible: !lightIcons MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - highlighted = true + if (mouse.button === Qt.LeftButton) { + highlighted = true + } else if (mouse.button === Qt.RightButton) { + contextMenu.popup() + } } onDoubleClicked: { target = true @@ -283,11 +289,28 @@ Item { id: text anchors.centerIn: parent text: adsbData + textFormat: TextEdit.RichText } MouseArea { anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - showAll = !showAll + if (mouse.button === Qt.LeftButton) { + showAll = !showAll + } else if (mouse.button === Qt.RightButton) { + contextMenu.popup() + } + } + Menu { + id: contextMenu + MenuItem { + text: "Set as target" + onTriggered: target = true + } + MenuItem { + text: "Find on feature map" + onTriggered: aircraftModel.findOnMap(index) + } } } } diff --git a/plugins/channelrx/demodadsb/osndb.h b/plugins/channelrx/demodadsb/osndb.h index d4741f8f7..87533550c 100644 --- a/plugins/channelrx/demodadsb/osndb.h +++ b/plugins/channelrx/demodadsb/osndb.h @@ -30,7 +30,7 @@ #include "util/csv.h" -#define OSNDB_URL "https://opensky-network.org/datasets/metadata/aircraftDatabase.csv" +#define OSNDB_URL "https://opensky-network.org/datasets/metadata/aircraftDatabase.zip" struct AircraftInformation { diff --git a/plugins/channelrx/demodadsb/readme.md b/plugins/channelrx/demodadsb/readme.md index 4ca7e5f75..5feb3ef2e 100644 --- a/plugins/channelrx/demodadsb/readme.md +++ b/plugins/channelrx/demodadsb/readme.md @@ -8,6 +8,10 @@ As well as displaying information received via ADS-B, the plugin can also combin ![ADS-B Demodulator plugin GUI](../../../doc/img/ADSBDemod_plugin.png) +The ADS-B plugin can send aicraft for display on the [Map Feature](../../feature/map/readme.md) alongside objects from other plugins and in 3D. + +![ADS-B on 3D Map](../../../doc/img/ADSBDemod_plugin_map_3d.png) +

Interface

![ADS-B Demodulator plugin settings](../../../doc/img/ADSBDemod_plugin_settings.png) @@ -262,6 +266,7 @@ The map displays aircraft locations and data geographically. Four types of map c ![ADS-B Demodulator Map](../../../doc/img/ADSBDemod_plugin_map2.png) The initial antenna location is placed according to My Position set under the Preferences > My Position menu. The position is only updated when the ADS-B demodulator plugin is first opened. +If My Position is not set correctly, the position of aircraft may not be computed correctly. Aircraft are only placed upon the map when a position can be calculated, which can require several frames to be received.