From 267ae135340b3fa2fbeec72798a2724a899c6915 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Wed, 9 Feb 2022 16:36:09 +0000 Subject: [PATCH] Add support for receiving global aircraft data from OpenSky Network. Add support for feeding ADS-B data to OpenSky Network. Fix binary Beast format feed. Fix display of USA and Japan flags. --- plugins/channelrx/demodadsb/adsbdemod.cpp | 184 ++++++- .../demodadsb/adsbdemodfeeddialog.cpp | 56 +- .../channelrx/demodadsb/adsbdemodfeeddialog.h | 8 +- .../demodadsb/adsbdemodfeeddialog.ui | 405 +++++++++++--- plugins/channelrx/demodadsb/adsbdemodgui.cpp | 521 ++++++++++++------ plugins/channelrx/demodadsb/adsbdemodgui.h | 9 + plugins/channelrx/demodadsb/adsbdemodgui.ui | 1 + .../channelrx/demodadsb/adsbdemodsettings.cpp | 66 ++- .../channelrx/demodadsb/adsbdemodsettings.h | 20 +- .../channelrx/demodadsb/adsbdemodworker.cpp | 149 ++++- plugins/channelrx/demodadsb/adsbdemodworker.h | 24 + plugins/channelrx/demodadsb/readme.md | 20 +- .../api/swagger/include/ADSBDemod.yaml | 40 +- .../code/qt5/client/SWGADSBDemodSettings.cpp | 423 ++++++++++++-- .../code/qt5/client/SWGADSBDemodSettings.h | 110 +++- 15 files changed, 1641 insertions(+), 395 deletions(-) diff --git a/plugins/channelrx/demodadsb/adsbdemod.cpp b/plugins/channelrx/demodadsb/adsbdemod.cpp index 3d3205ee3..312ec149d 100644 --- a/plugins/channelrx/demodadsb/adsbdemod.cpp +++ b/plugins/channelrx/demodadsb/adsbdemod.cpp @@ -206,16 +206,55 @@ void ADSBDemod::applySettings(const ADSBDemodSettings& settings, bool force) reverseAPIKeys.append("removeTimeout"); } if ((settings.m_feedEnabled != m_settings.m_feedEnabled) || force) { - reverseAPIKeys.append("beastEnabled"); + reverseAPIKeys.append("feedEnabled"); } - if ((settings.m_feedHost != m_settings.m_feedHost) || force) { - reverseAPIKeys.append("beastHost"); + if ((settings.m_exportClientEnabled != m_settings.m_exportClientEnabled) || force) { + reverseAPIKeys.append("exportClientEnabled"); } - if ((settings.m_feedPort != m_settings.m_feedPort) || force) { - reverseAPIKeys.append("beastPort"); + if ((settings.m_exportClientHost != m_settings.m_exportClientHost) || force) { + reverseAPIKeys.append("exportClientHost"); } - if ((settings.m_feedFormat != m_settings.m_feedFormat) || force) { - reverseAPIKeys.append("feedFormat"); + if ((settings.m_exportClientPort != m_settings.m_exportClientPort) || force) { + reverseAPIKeys.append("exportClientPort"); + } + if ((settings.m_exportClientFormat != m_settings.m_exportClientFormat) || force) { + reverseAPIKeys.append("exportClientFormat"); + } + if ((settings.m_exportServerEnabled != m_settings.m_exportServerEnabled) || force) { + reverseAPIKeys.append("exportServerEnabled"); + } + if ((settings.m_exportServerPort != m_settings.m_exportServerPort) || force) { + reverseAPIKeys.append("exportServerPort"); + } + if ((settings.m_importEnabled != m_settings.m_importEnabled) || force) { + reverseAPIKeys.append("importEnabled"); + } + if ((settings.m_importHost != m_settings.m_importHost) || force) { + reverseAPIKeys.append("importHost"); + } + if ((settings.m_importUsername != m_settings.m_importUsername) || force) { + reverseAPIKeys.append("importUsername"); + } + if ((settings.m_importPassword != m_settings.m_importPassword) || force) { + reverseAPIKeys.append("importPassword"); + } + if ((settings.m_importParameters != m_settings.m_importParameters) || force) { + reverseAPIKeys.append("importParameters"); + } + if ((settings.m_importPeriod != m_settings.m_importPeriod) || force) { + reverseAPIKeys.append("importPeriod"); + } + if ((settings.m_importMinLatitude != m_settings.m_importMinLatitude) || force) { + reverseAPIKeys.append("importMinLatitude"); + } + if ((settings.m_importMaxLatitude != m_settings.m_importMaxLatitude) || force) { + reverseAPIKeys.append("importMaxLatitude"); + } + if ((settings.m_importMinLongitude != m_settings.m_importMinLongitude) || force) { + reverseAPIKeys.append("importMinLongitude"); + } + if ((settings.m_importMaxLongitude != m_settings.m_importMaxLongitude) || force) { + reverseAPIKeys.append("importMaxLongitude"); } if ((settings.m_logFilename != m_settings.m_logFilename) || force) { reverseAPIKeys.append("logFilename"); @@ -363,17 +402,56 @@ void ADSBDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("removeTimeout")) { settings.m_removeTimeout = response.getAdsbDemodSettings()->getRemoveTimeout(); } - if (channelSettingsKeys.contains("beastEnabled")) { - settings.m_feedEnabled = response.getAdsbDemodSettings()->getBeastEnabled() != 0; + if (channelSettingsKeys.contains("feedEnabled")) { + settings.m_feedEnabled = response.getAdsbDemodSettings()->getFeedEnabled() != 0; } - if (channelSettingsKeys.contains("beastHost")) { - settings.m_feedHost = *response.getAdsbDemodSettings()->getBeastHost(); + if (channelSettingsKeys.contains("exportClientEnabled")) { + settings.m_exportClientEnabled = response.getAdsbDemodSettings()->getExportClientEnabled() != 0; } - if (channelSettingsKeys.contains("beastPort")) { - settings.m_feedPort = response.getAdsbDemodSettings()->getBeastPort(); + if (channelSettingsKeys.contains("exportClientHost")) { + settings.m_exportClientHost = *response.getAdsbDemodSettings()->getExportClientHost(); } - if (channelSettingsKeys.contains("feedFormat")) { - settings.m_feedFormat = (ADSBDemodSettings::FeedFormat) response.getAdsbDemodSettings()->getFeedFormat(); + if (channelSettingsKeys.contains("exportClientPort")) { + settings.m_exportClientPort = response.getAdsbDemodSettings()->getExportClientPort(); + } + if (channelSettingsKeys.contains("exportClientFormat")) { + settings.m_exportClientFormat = (ADSBDemodSettings::FeedFormat) response.getAdsbDemodSettings()->getExportClientFormat(); + } + if (channelSettingsKeys.contains("exportServerEnabled")) { + settings.m_exportServerEnabled = response.getAdsbDemodSettings()->getExportServerEnabled() != 0; + } + if (channelSettingsKeys.contains("exportServerPort")) { + settings.m_exportServerPort = response.getAdsbDemodSettings()->getExportServerPort(); + } + if (channelSettingsKeys.contains("importEnabled")) { + settings.m_importEnabled = response.getAdsbDemodSettings()->getImportEnabled() != 0; + } + if (channelSettingsKeys.contains("importHost")) { + settings.m_importHost = *response.getAdsbDemodSettings()->getImportHost(); + } + if (channelSettingsKeys.contains("importUsername")) { + settings.m_importUsername = *response.getAdsbDemodSettings()->getImportUsername(); + } + if (channelSettingsKeys.contains("importPassword")) { + settings.m_importPassword = *response.getAdsbDemodSettings()->getImportPassword(); + } + if (channelSettingsKeys.contains("importParameters")) { + settings.m_importParameters = *response.getAdsbDemodSettings()->getImportParameters(); + } + if (channelSettingsKeys.contains("importPeriod")) { + settings.m_importPeriod = response.getAdsbDemodSettings()->getImportPeriod(); + } + if (channelSettingsKeys.contains("importMinLatitude")) { + settings.m_importMinLatitude = *response.getAdsbDemodSettings()->getImportMinLatitude(); + } + if (channelSettingsKeys.contains("importMaxLatitude")) { + settings.m_importMaxLatitude = *response.getAdsbDemodSettings()->getImportMaxLatitude(); + } + if (channelSettingsKeys.contains("importMinLongitude")) { + settings.m_importMinLongitude = *response.getAdsbDemodSettings()->getImportMinLongitude(); + } + if (channelSettingsKeys.contains("importMaxLongitude")) { + settings.m_importMaxLongitude = *response.getAdsbDemodSettings()->getImportMaxLongitude(); } if (channelSettingsKeys.contains("logFilename")) { settings.m_logFilename = *response.getAdsbDemodSettings()->getLogFilename(); @@ -435,10 +513,23 @@ void ADSBDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res response.getAdsbDemodSettings()->setInterpolatorPhaseSteps(settings.m_interpolatorPhaseSteps); response.getAdsbDemodSettings()->setInterpolatorTapsPerPhase(settings.m_interpolatorTapsPerPhase); response.getAdsbDemodSettings()->setRemoveTimeout(settings.m_removeTimeout); - response.getAdsbDemodSettings()->setBeastEnabled(settings.m_feedEnabled ? 1 : 0); - response.getAdsbDemodSettings()->setBeastHost(new QString(settings.m_feedHost)); - response.getAdsbDemodSettings()->setBeastPort(settings.m_feedPort); - response.getAdsbDemodSettings()->setFeedFormat((int) settings.m_feedFormat); + response.getAdsbDemodSettings()->setFeedEnabled(settings.m_feedEnabled ? 1 : 0); + response.getAdsbDemodSettings()->setExportClientEnabled(settings.m_exportClientEnabled ? 1 : 0); + response.getAdsbDemodSettings()->setExportClientHost(new QString(settings.m_exportClientHost)); + response.getAdsbDemodSettings()->setExportClientPort(settings.m_exportClientPort); + response.getAdsbDemodSettings()->setExportClientFormat((int) settings.m_exportClientFormat); + response.getAdsbDemodSettings()->setExportServerEnabled(settings.m_exportServerEnabled ? 1 : 0); + response.getAdsbDemodSettings()->setExportServerPort(settings.m_exportServerPort); + response.getAdsbDemodSettings()->setImportEnabled(settings.m_importEnabled ? 1 : 0); + response.getAdsbDemodSettings()->setImportHost(new QString(settings.m_importHost)); + response.getAdsbDemodSettings()->setImportUsername(new QString(settings.m_importUsername)); + response.getAdsbDemodSettings()->setImportPassword(new QString(settings.m_importPassword)); + response.getAdsbDemodSettings()->setImportParameters(new QString(settings.m_importParameters)); + response.getAdsbDemodSettings()->setImportPeriod(settings.m_importPeriod); + response.getAdsbDemodSettings()->setImportMinLatitude(new QString(settings.m_importMinLatitude)); + response.getAdsbDemodSettings()->setImportMaxLatitude(new QString(settings.m_importMaxLatitude)); + response.getAdsbDemodSettings()->setImportMinLongitude(new QString(settings.m_importMinLongitude)); + response.getAdsbDemodSettings()->setImportMaxLongitude(new QString(settings.m_importMaxLongitude)); response.getAdsbDemodSettings()->setRgbColor(settings.m_rgbColor); response.getAdsbDemodSettings()->setLogFilename(new QString(settings.m_logFilename)); response.getAdsbDemodSettings()->setLogEnabled(settings.m_logEnabled); @@ -548,17 +639,56 @@ void ADSBDemod::webapiReverseSendSettings(QList& channelSettingsKeys, c if (channelSettingsKeys.contains("removeTimeout") || force) { swgADSBDemodSettings->setRemoveTimeout(settings.m_removeTimeout); } - if (channelSettingsKeys.contains("beastEnabled") || force) { - swgADSBDemodSettings->setBeastEnabled(settings.m_feedEnabled ? 1 : 0); + if (channelSettingsKeys.contains("feedEnabled") || force) { + swgADSBDemodSettings->setFeedEnabled(settings.m_feedEnabled ? 1 : 0); } - if (channelSettingsKeys.contains("beastHost") || force) { - swgADSBDemodSettings->setBeastHost(new QString(settings.m_feedHost)); + if (channelSettingsKeys.contains("exportClientEnabled") || force) { + swgADSBDemodSettings->setExportClientEnabled(settings.m_exportClientEnabled ? 1 : 0); } - if (channelSettingsKeys.contains("beastPort") || force) { - swgADSBDemodSettings->setBeastPort(settings.m_feedPort); + if (channelSettingsKeys.contains("exportClientHost") || force) { + swgADSBDemodSettings->setExportClientHost(new QString(settings.m_exportClientHost)); } - if (channelSettingsKeys.contains("feedFormat") || force) { - swgADSBDemodSettings->setFeedFormat((int) settings.m_feedFormat); + if (channelSettingsKeys.contains("exportClientPort") || force) { + swgADSBDemodSettings->setExportClientPort(settings.m_exportClientPort); + } + if (channelSettingsKeys.contains("exportClientFormat") || force) { + swgADSBDemodSettings->setExportClientFormat((int) settings.m_exportClientFormat); + } + if (channelSettingsKeys.contains("exportServerEnabled") || force) { + swgADSBDemodSettings->setExportServerEnabled(settings.m_exportServerEnabled ? 1 : 0); + } + if (channelSettingsKeys.contains("exportServerPort") || force) { + swgADSBDemodSettings->setExportServerPort(settings.m_exportServerPort); + } + if (channelSettingsKeys.contains("importEnabled") || force) { + swgADSBDemodSettings->setImportEnabled(settings.m_importEnabled ? 1 : 0); + } + if (channelSettingsKeys.contains("importHost") || force) { + swgADSBDemodSettings->setImportHost(new QString(settings.m_importHost)); + } + if (channelSettingsKeys.contains("importUsername") || force) { + swgADSBDemodSettings->setImportUsername(new QString(settings.m_importUsername)); + } + if (channelSettingsKeys.contains("importPassword") || force) { + swgADSBDemodSettings->setImportPassword(new QString(settings.m_importPassword)); + } + if (channelSettingsKeys.contains("importParameters") || force) { + swgADSBDemodSettings->setImportParameters(new QString(settings.m_importParameters)); + } + if (channelSettingsKeys.contains("importPeriod") || force) { + swgADSBDemodSettings->setImportPeriod(settings.m_importPeriod); + } + if (channelSettingsKeys.contains("importMinLatitude") || force) { + swgADSBDemodSettings->setImportMinLatitude(new QString(settings.m_importMinLatitude)); + } + if (channelSettingsKeys.contains("importMaxLatitude") || force) { + swgADSBDemodSettings->setImportMaxLatitude(new QString(settings.m_importMaxLatitude)); + } + if (channelSettingsKeys.contains("importMinLongitude") || force) { + swgADSBDemodSettings->setImportMinLongitude(new QString(settings.m_importMinLongitude)); + } + if (channelSettingsKeys.contains("importMaxLongitude") || force) { + swgADSBDemodSettings->setImportMaxLongitude(new QString(settings.m_importMaxLongitude)); } if (channelSettingsKeys.contains("logFilename") || force) { swgADSBDemodSettings->setLogFilename(new QString(settings.m_logFilename)); diff --git a/plugins/channelrx/demodadsb/adsbdemodfeeddialog.cpp b/plugins/channelrx/demodadsb/adsbdemodfeeddialog.cpp index 4eaaac506..a5bceeec5 100644 --- a/plugins/channelrx/demodadsb/adsbdemodfeeddialog.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodfeeddialog.cpp @@ -20,14 +20,28 @@ #include "adsbdemodfeeddialog.h" #include "adsbdemodsettings.h" -ADSBDemodFeedDialog::ADSBDemodFeedDialog(QString& feedHost, int feedPort, ADSBDemodSettings::FeedFormat feedFormat, QWidget* parent) : +ADSBDemodFeedDialog::ADSBDemodFeedDialog(ADSBDemodSettings *settings, QWidget* parent) : QDialog(parent), + m_settings(settings), ui(new Ui::ADSBDemodFeedDialog) { ui->setupUi(this); - ui->host->lineEdit()->setText(feedHost); - ui->port->setValue(feedPort); - ui->format->setCurrentIndex((int)feedFormat); + ui->exportClientEnabled->setChecked(m_settings->m_exportClientEnabled); + ui->exportClientHost->lineEdit()->setText(m_settings->m_exportClientHost); + ui->exportClientPort->setValue(m_settings->m_exportClientPort); + ui->exportClientFormat->setCurrentIndex((int)m_settings->m_exportClientFormat); + ui->exportServerEnabled->setChecked(m_settings->m_exportServerEnabled); + ui->exportServerPort->setValue(m_settings->m_exportServerPort); + ui->importEnabled->setChecked(m_settings->m_importEnabled); + ui->importHost->setCurrentIndex(ui->importHost->findText(m_settings->m_importHost)); + ui->importUsername->setText(m_settings->m_importUsername); + ui->importPassword->setText(m_settings->m_importPassword); + ui->importParameters->setText(m_settings->m_importParameters); + ui->importPeriod->setValue(m_settings->m_importPeriod); + ui->latitudeMin->setText(m_settings->m_importMinLatitude); + ui->latitudeMax->setText(m_settings->m_importMaxLatitude); + ui->longitudeMin->setText(m_settings->m_importMinLongitude); + ui->longitudeMax->setText(m_settings->m_importMaxLongitude); } ADSBDemodFeedDialog::~ADSBDemodFeedDialog() @@ -37,24 +51,38 @@ ADSBDemodFeedDialog::~ADSBDemodFeedDialog() void ADSBDemodFeedDialog::accept() { - m_feedHost = ui->host->currentText(); - m_feedPort = ui->port->value(); - m_feedFormat = (ADSBDemodSettings::FeedFormat )ui->format->currentIndex(); + m_settings->m_exportClientEnabled = ui->exportClientEnabled->isChecked(); + m_settings->m_exportClientHost = ui->exportClientHost->currentText(); + m_settings->m_exportClientPort = ui->exportClientPort->value(); + m_settings->m_exportClientFormat = (ADSBDemodSettings::FeedFormat )ui->exportClientFormat->currentIndex(); + m_settings->m_exportServerEnabled = ui->exportServerEnabled->isChecked(); + m_settings->m_exportServerPort = ui->exportServerPort->value(); + m_settings->m_importEnabled = ui->importEnabled->isChecked(); + m_settings->m_importHost = ui->importHost->currentText(); + m_settings->m_importUsername = ui->importUsername->text(); + m_settings->m_importPassword = ui->importPassword->text(); + m_settings->m_importParameters = ui->importParameters->text(); + m_settings->m_importPeriod = ui->importPeriod->value(); + m_settings->m_importMinLatitude = ui->latitudeMin->text(); + m_settings->m_importMaxLatitude = ui->latitudeMax->text(); + m_settings->m_importMinLongitude = ui->longitudeMin->text(); + m_settings->m_importMaxLongitude = ui->longitudeMax->text(); + QDialog::accept(); } -void ADSBDemodFeedDialog::on_host_currentIndexChanged(int value) +void ADSBDemodFeedDialog::on_exportClientHost_currentIndexChanged(int value) { if (value == 0) { - ui->host->lineEdit()->setText("feed.adsbexchange.com"); - ui->port->setValue(30005); - ui->format->setCurrentIndex(0); + ui->exportClientHost->lineEdit()->setText("feed.adsbexchange.com"); + ui->exportClientPort->setValue(30005); + ui->exportClientFormat->setCurrentIndex(0); } else if (value == 1) { - ui->host->lineEdit()->setText("data.adsbhub.org"); - ui->port->setValue(5002); - ui->format->setCurrentIndex(1); + ui->exportClientHost->lineEdit()->setText("data.adsbhub.org"); + ui->exportClientPort->setValue(5002); + ui->exportClientFormat->setCurrentIndex(1); } } diff --git a/plugins/channelrx/demodadsb/adsbdemodfeeddialog.h b/plugins/channelrx/demodadsb/adsbdemodfeeddialog.h index 64af99183..e3a2b162a 100644 --- a/plugins/channelrx/demodadsb/adsbdemodfeeddialog.h +++ b/plugins/channelrx/demodadsb/adsbdemodfeeddialog.h @@ -25,16 +25,14 @@ class ADSBDemodFeedDialog : public QDialog { Q_OBJECT public: - explicit ADSBDemodFeedDialog(QString& feedHost, int feedPort, ADSBDemodSettings::FeedFormat feedFormat, QWidget* parent = 0); + explicit ADSBDemodFeedDialog(ADSBDemodSettings *settings, QWidget* parent = 0); ~ADSBDemodFeedDialog(); - QString m_feedHost; - int m_feedPort; - ADSBDemodSettings::FeedFormat m_feedFormat; + ADSBDemodSettings *m_settings; private slots: void accept(); - void on_host_currentIndexChanged(int value); + void on_exportClientHost_currentIndexChanged(int value); private: Ui::ADSBDemodFeedDialog* ui; diff --git a/plugins/channelrx/demodadsb/adsbdemodfeeddialog.ui b/plugins/channelrx/demodadsb/adsbdemodfeeddialog.ui index 786c2c4ac..19b6c8283 100644 --- a/plugins/channelrx/demodadsb/adsbdemodfeeddialog.ui +++ b/plugins/channelrx/demodadsb/adsbdemodfeeddialog.ui @@ -6,13 +6,12 @@ 0 0 - 351 - 138 + 472 + 553 - Liberation Sans 9 @@ -23,75 +22,334 @@ - - - - Server hostname + + + + Import + + + + + Parameters + + + + + + + Username to access server with + + + + + + + + + Latitude Min + + + + + + + Minimum latitude of area to receive aircraft data from + + + + + + + Latitude Max + + + + + + + Maximum latitude of area to receive aircraft data from + + + + + + + Minimum longitude of area to receive aircraft data from + + + Longitude Min + + + + + + + + + + Longitude Max + + + + + + + Maximum longitude of area to receive aircraft data from + + + + + + + + + Server hostname + + + + + + + Username + + + + + + + Update period (s) + + + + + + + + + + + + + + + 100 + 0 + + + + Enable import + + + + + + + Password to access the server with + + + + + + + Parameters for the API call such as geographic location + + + + + + + Time period in seconds between updates requested from the server + + + 0 + + + 5.000000000000000 + + + 1000.000000000000000 + + + 10.000000000000000 + + + + + + + Hostname of server to receive ADS-B data from + + + + opensky-network.org + + + + + + + + Password + + + + - - - - Port number + + + + Export Client + + + + + + 100 + 0 + + + + Enable client + + + + + + + Enable TCP client + + + + + + + + + + Server hostname + + + + + + + Hostname of server to feed ADS-B data to + + + true + + + + feed.adsbexchange.com + + + + + data.adsbhub.org + + + + + + + + Port + + + + + + + The TCP port number the server is listening on + + + 1024 + + + 65535 + + + + + + + Format + + + + + + + Format to feed the data to the server in + + + + Beast binary + + + + + Beast hex + + + + + - - - - The TCP port number the server is listening on + + + + Export Server - - 1024 - - - 65535 - - - - - - - Format to feed the data to the server in - - - - Beast binary - - - - - Beast hex - - - - - - - - Format - - - - - - - Hostname of server to feed ADS-B data to - - - true - - - - feed.adsbexchange.com - - - - - data.adsbhub.org - - + + + + + Port + + + + + + + TCP port number to listen for connections on + + + 1024 + + + 65535 + + + + + + + + 100 + 0 + + + + Enable server + + + + + + + Enable TCP server + + + + + + + @@ -110,7 +368,22 @@ - port + exportClientEnabled + exportClientHost + exportClientPort + exportClientFormat + exportServerEnabled + exportServerPort + importEnabled + importHost + importUsername + importPassword + importParameters + importPeriod + latitudeMin + latitudeMax + longitudeMin + longitudeMax diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index e7d600efd..7dec4d67c 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include @@ -859,65 +861,11 @@ QIcon *ADSBDemodGUI::getFlagIcon(const QString &country) } } -void ADSBDemodGUI::handleADSB( - const QByteArray data, - const QDateTime dateTime, - float correlation, - float correlationOnes, - bool updateModel) +// Find aircraft with icao, or create if it doesn't exist +Aircraft *ADSBDemodGUI::getAircraft(int icao, bool &newAircraft) { - const char idMap[] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ############-##0123456789######"; - const QString categorySetA[] = { - QStringLiteral("None"), - QStringLiteral("Light"), - QStringLiteral("Small"), - QStringLiteral("Large"), - QStringLiteral("High vortex"), - QStringLiteral("Heavy"), - QStringLiteral("High performance"), - QStringLiteral("Rotorcraft") - }; - const QString categorySetB[] = { - QStringLiteral("None"), - QStringLiteral("Glider/sailplane"), - QStringLiteral("Lighter-than-air"), - QStringLiteral("Parachutist"), - QStringLiteral("Ultralight"), - QStringLiteral("Reserved"), - QStringLiteral("UAV"), - QStringLiteral("Space vehicle") - }; - const QString categorySetC[] = { - QStringLiteral("None"), - QStringLiteral("Emergency vehicle"), - QStringLiteral("Service vehicle"), - QStringLiteral("Ground obstruction"), - QStringLiteral("Cluster obstacle"), - QStringLiteral("Line obstacle"), - QStringLiteral("Reserved"), - QStringLiteral("Reserved") - }; - const QString emergencyStatus[] = { - 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 resetAnimation = false; - - 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 - int tc = (data[4] >> 3) & 0x1f; // Type code - Aircraft *aircraft; + if (m_aircraft.contains(icao)) { // Update existing aircraft info @@ -931,12 +879,7 @@ void ADSBDemodGUI::handleADSB( 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_icaoHex)); - } else { - aircraft->m_icaoItem->setText(aircraft->m_icaoHex); - } + aircraft->m_icaoItem->setText(aircraft->m_icaoHex); ui->adsbData->setSortingEnabled(false); int row = ui->adsbData->rowCount(); ui->adsbData->setRowCount(row + 1); @@ -1020,20 +963,30 @@ void ADSBDemodGUI::handleADSB( // Some countries use AA-A - try these first as first letters are common prefix = aircraft->m_aircraftInfo->m_registration.left(idx + 2); if (m_prefixMap->contains(prefix)) - flag = m_prefixMap->value(prefix); + flag = m_prefixMap->value(prefix); else { // Try letters before '-' prefix = aircraft->m_aircraftInfo->m_registration.left(idx); if (m_prefixMap->contains(prefix)) - flag = m_prefixMap->value(prefix); + flag = m_prefixMap->value(prefix); } } else { - // No '-' Could be military - if ((m_militaryMap != nullptr) && (m_militaryMap->contains(aircraft->m_aircraftInfo->m_operator))) + // No '-' Could be one of a few countries or military. + // See: https://en.wikipedia.org/wiki/List_of_aircraft_registration_prefixes + if (aircraft->m_aircraftInfo->m_registration.startsWith("N")) { + flag = m_prefixMap->value("N"); // US + } else if (aircraft->m_aircraftInfo->m_registration.startsWith("JA")) { + flag = m_prefixMap->value("JA"); // Japan + } else if (aircraft->m_aircraftInfo->m_registration.startsWith("HL")) { + flag = m_prefixMap->value("HL"); // Korea + } else if (aircraft->m_aircraftInfo->m_registration.startsWith("YV")) { + flag = m_prefixMap->value("YV"); // Venezuela + } else if ((m_militaryMap != nullptr) && (m_militaryMap->contains(aircraft->m_aircraftInfo->m_operator))) { flag = m_militaryMap->value(aircraft->m_aircraftInfo->m_operator); + } } if (flag != "") { @@ -1070,6 +1023,70 @@ void ADSBDemodGUI::handleADSB( // Check to see if we need to emit a notification about this new aircraft checkStaticNotification(aircraft); } + + return aircraft; +} + +void ADSBDemodGUI::handleADSB( + const QByteArray data, + const QDateTime dateTime, + float correlation, + float correlationOnes, + bool updateModel) +{ + const char idMap[] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ############-##0123456789######"; + const QString categorySetA[] = { + QStringLiteral("None"), + QStringLiteral("Light"), + QStringLiteral("Small"), + QStringLiteral("Large"), + QStringLiteral("High vortex"), + QStringLiteral("Heavy"), + QStringLiteral("High performance"), + QStringLiteral("Rotorcraft") + }; + const QString categorySetB[] = { + QStringLiteral("None"), + QStringLiteral("Glider/sailplane"), + QStringLiteral("Lighter-than-air"), + QStringLiteral("Parachutist"), + QStringLiteral("Ultralight"), + QStringLiteral("Reserved"), + QStringLiteral("UAV"), + QStringLiteral("Space vehicle") + }; + const QString categorySetC[] = { + QStringLiteral("None"), + QStringLiteral("Emergency vehicle"), + QStringLiteral("Service vehicle"), + QStringLiteral("Ground obstruction"), + QStringLiteral("Cluster obstacle"), + QStringLiteral("Line obstacle"), + QStringLiteral("Reserved"), + QStringLiteral("Reserved") + }; + const QString emergencyStatus[] = { + 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 resetAnimation = false; + + 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 + int tc = (data[4] >> 3) & 0x1f; // Type code + + Aircraft *aircraft = getAircraft(icao, newAircraft); + aircraft->m_time = dateTime; QTime time = dateTime.time(); aircraft->m_timeItem->setText(QString("%1:%2:%3").arg(time.hour(), 2, 10, QLatin1Char('0')).arg(time.minute(), 2, 10, QLatin1Char('0')).arg(time.second(), 2, 10, QLatin1Char('0'))); @@ -1171,94 +1188,7 @@ void ADSBDemodGUI::handleADSB( ) ) { - QString aircraftType; - - if (!aircraft->m_emitterCategory.compare("Heavy")) - { - QStringList heavy = {"B744", "B77W", "B788", "A388"}; - aircraftType = heavy[m_random.bounded(heavy.size())]; - } - else if (!aircraft->m_emitterCategory.compare("Large")) - { - QStringList large = {"A319", "A320", "A321", "B737", "B738", "B739"}; - aircraftType = large[m_random.bounded(large.size())]; - } - 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()) - { - aircraft->m_aircraftCat3DModel = ""; - 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); - } - } + get3DModelBasedOnCategory(aircraft); // As we're changing the model, we need to reset animations to // ensure gear/flaps are in correct position on new model resetAnimation = true; @@ -2314,6 +2244,7 @@ void ADSBDemodGUI::on_feed_clicked(bool checked) m_settings.m_feedEnabled = checked; // Don't disable host/port - so they can be entered before connecting applySettings(); + applyImportSettings(); } void ADSBDemodGUI::on_notifications_clicked() @@ -3001,6 +2932,98 @@ void ADSBDemodGUI::get3DModel(Aircraft *aircraft) } } +void ADSBDemodGUI::get3DModelBasedOnCategory(Aircraft *aircraft) +{ + QString aircraftType; + + if (!aircraft->m_emitterCategory.compare("Heavy")) + { + QStringList heavy = {"B744", "B77W", "B788", "A388"}; + aircraftType = heavy[m_random.bounded(heavy.size())]; + } + else if (!aircraft->m_emitterCategory.compare("Large")) + { + QStringList large = {"A319", "A320", "A321", "B737", "B738", "B739"}; + aircraftType = large[m_random.bounded(large.size())]; + } + 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()) + { + aircraft->m_aircraftCat3DModel = ""; + 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); + } + } +} + void ADSBDemodGUI::update3DModels() { // Look for all aircraft gltfs in 3d directory @@ -3399,6 +3422,8 @@ void ADSBDemodGUI::updatePhotoText(Aircraft *aircraft) QList sizes = icon.availableSizes(); if (sizes.size() > 0) { ui->photoFlag->setPixmap(icon.pixmap(sizes[0])); + } else { + ui->photoFlag->setPixmap(QPixmap()); } updatePhotoFlightInformation(aircraft); @@ -3512,13 +3537,11 @@ void ADSBDemodGUI::highlightAircraft(Aircraft *aircraft) // Show feed dialog void ADSBDemodGUI::feedSelect() { - ADSBDemodFeedDialog dialog(m_settings.m_feedHost, m_settings.m_feedPort, m_settings.m_feedFormat); + ADSBDemodFeedDialog dialog(&m_settings); if (dialog.exec() == QDialog::Accepted) { - m_settings.m_feedHost = dialog.m_feedHost; - m_settings.m_feedPort = dialog.m_feedPort; - m_settings.m_feedFormat = dialog.m_feedFormat; applySettings(); + applyImportSettings(); } } @@ -3799,6 +3822,11 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb displaySettings(); applySettings(true); + connect(&m_importTimer, &QTimer::timeout, this, &ADSBDemodGUI::import); + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleImportReply(QNetworkReply*))); + applyImportSettings(); + ui->map->installEventFilter(this); } @@ -3832,6 +3860,7 @@ ADSBDemodGUI::~ADSBDemodGUI() qDeleteAll(m_airspaces); qDeleteAll(m_navAids); qDeleteAll(m_3DModelMatch); + delete m_networkManager; } void ADSBDemodGUI::applySettings(bool force) @@ -3940,6 +3969,7 @@ void ADSBDemodGUI::displaySettings() initFlightInformation(); applyMapSettings(); + applyImportSettings(); restoreState(m_rollupState); blockApplySettings(false); @@ -4384,3 +4414,176 @@ bool ADSBDemodGUI::eventFilter(QObject *obj, QEvent *event) } return false; } + +void ADSBDemodGUI::applyImportSettings() +{ + m_importTimer.setInterval(m_settings.m_importPeriod * 1000); + if (m_settings.m_feedEnabled && m_settings.m_importEnabled) { + m_importTimer.start(); + } else { + m_importTimer.stop(); + } +} + +// Import ADS-B data from opensky-network via an API call +void ADSBDemodGUI::import() +{ + QString urlString = "https://"; + if (!m_settings.m_importUsername.isEmpty() && !m_settings.m_importPassword.isEmpty()) { + urlString = urlString + m_settings.m_importUsername + ":" + m_settings.m_importPassword + "@"; + } + urlString = urlString + m_settings.m_importHost + "/api/states/all"; + QChar join = '?'; + if (!m_settings.m_importParameters.isEmpty()) + { + urlString = urlString + join + m_settings.m_importParameters; + join = '&'; + } + if (!m_settings.m_importMinLatitude.isEmpty()) + { + urlString = urlString + join + "lamin=" + m_settings.m_importMinLatitude; + join = '&'; + } + if (!m_settings.m_importMaxLatitude.isEmpty()) + { + urlString = urlString + join + "lamax=" + m_settings.m_importMaxLatitude; + join = '&'; + } + if (!m_settings.m_importMinLongitude.isEmpty()) + { + urlString = urlString + join + "lomin=" + m_settings.m_importMinLongitude; + join = '&'; + } + if (!m_settings.m_importMaxLongitude.isEmpty()) + { + urlString = urlString + join + "lomax=" + m_settings.m_importMaxLongitude; + join = '&'; + } + m_networkManager->get(QNetworkRequest(QUrl(urlString))); +} + +// Handle opensky-network API call reply +void ADSBDemodGUI::handleImportReply(QNetworkReply* reply) +{ + if (reply) + { + if (!reply->error()) + { + QJsonDocument document = QJsonDocument::fromJson(reply->readAll()); + if (document.isObject()) + { + QJsonObject obj = document.object(); + if (obj.contains("time") && obj.contains("states")) + { + int seconds = obj.value("time").toInt(); + QDateTime dateTime = QDateTime::fromSecsSinceEpoch(seconds); + QJsonArray states = obj.value("states").toArray(); + for (int i = 0; i < states.size(); i++) + { + QJsonArray state = states[i].toArray(); + int icao = state[0].toString().toInt(nullptr, 16); + + bool newAircraft; + Aircraft *aircraft = getAircraft(icao, newAircraft); + + QString callsign = state[1].toString().trimmed(); + if (!callsign.isEmpty()) + { + aircraft->m_callsign = callsign; + aircraft->m_callsignItem->setText(aircraft->m_callsign); + } + + QDateTime timePosition = dateTime; + if (state[3].isNull()) { + timePosition = dateTime.addSecs(-15); // At least 15 seconds old + } else { + timePosition = QDateTime::fromSecsSinceEpoch(state[3].toInt()); + } + aircraft->m_time = QDateTime::fromSecsSinceEpoch(state[4].toInt()); + QTime time = aircraft->m_time.time(); + aircraft->m_timeItem->setText(QString("%1:%2:%3").arg(time.hour(), 2, 10, QLatin1Char('0')).arg(time.minute(), 2, 10, QLatin1Char('0')).arg(time.second(), 2, 10, QLatin1Char('0'))); + aircraft->m_adsbFrameCount++; + aircraft->m_adsbFrameCountItem->setData(Qt::DisplayRole, aircraft->m_adsbFrameCount); + + if (timePosition > aircraft->m_positionDateTime) + { + if (!state[5].isNull() && !state[6].isNull()) + { + aircraft->m_longitude = state[5].toDouble(); + aircraft->m_latitude = state[6].toDouble(); + aircraft->m_longitudeItem->setData(Qt::DisplayRole, aircraft->m_longitude); + aircraft->m_latitudeItem->setData(Qt::DisplayRole, aircraft->m_latitude); + updatePosition(aircraft); + aircraft->m_cprValid[0] = false; + aircraft->m_cprValid[1] = false; + } + if (!state[7].isNull()) + { + aircraft->m_altitude = (int)Units::metresToFeet(state[7].toDouble()); + aircraft->m_altitudeValid = true; + aircraft->m_altitudeGNSS = false; + aircraft->m_altitudeItem->setData(Qt::DisplayRole, aircraft->m_altitude); + } + aircraft->m_positionDateTime = timePosition; + } + aircraft->m_onSurface = state[8].toBool(false); + if (!state[9].isNull()) + { + aircraft->m_speed = (int)state[9].toDouble(); + aircraft->m_speedItem->setData(Qt::DisplayRole, aircraft->m_speed); + aircraft->m_speedValid = true; + aircraft->m_speedType = Aircraft::GS; + } + if (!state[10].isNull()) + { + aircraft->m_heading = (float)state[10].toDouble(); + aircraft->m_headingItem->setData(Qt::DisplayRole, std::round(aircraft->m_heading)); + aircraft->m_headingValid = true; + aircraft->m_headingDateTime = aircraft->m_time; + } + if (!state[11].isNull()) + { + aircraft->m_verticalRate = (int)state[10].toDouble(); + aircraft->m_verticalRateItem->setData(Qt::DisplayRole, aircraft->m_verticalRate); + aircraft->m_verticalRateValid = true; + } + if (!state[14].isNull()) + { + aircraft->m_squawk = state[14].toString().toInt(); + aircraft->m_squawkItem->setText(QString("%1").arg(aircraft->m_squawk, 4, 10, QLatin1Char('0'))); + } + + // Update aircraft in map + if (aircraft->m_positionValid) + { + // Check to see if we need to start any animations + QList *animations = animate(dateTime, aircraft); + + // Update map displayed in channel + m_aircraftModel.aircraftUpdated(aircraft); + + // Send to Map feature + sendToMap(aircraft, animations); + } + + // Check to see if we need to emit a notification about this aircraft + checkDynamicNotification(aircraft); + } + } + else + { + qDebug() << "ADSBDemodGUI::handleImportReply: Document object does not contain time and states: " << document; + } + } + else + { + qDebug() << "ADSBDemodGUI::handleImportReply: Document is not an object: " << document; + } + } + else + { + qDebug() << "ADSBDemodGUI::handleImportReply: error " << reply->error(); + } + reply->deleteLater(); + } +} diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.h b/plugins/channelrx/demodadsb/adsbdemodgui.h index 7f49bbb9b..8ca93d000 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.h +++ b/plugins/channelrx/demodadsb/adsbdemodgui.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "channel/channelgui.h" #include "dsp/dsptypes.h" @@ -760,6 +761,7 @@ public: QString get3DModel(const QString &aircraft, const QString &operatorICAO) const; QString get3DModel(const QString &aircraft); void get3DModel(Aircraft *aircraft); + void get3DModelBasedOnCategory(Aircraft *aircraft); public slots: void channelMarkerChangedByCursor(); @@ -824,6 +826,9 @@ private: QHash m_modelAltitudeOffset; QHash m_labelAltitudeOffset; + QTimer m_importTimer; + QNetworkAccessManager *m_networkManager; + explicit ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0); virtual ~ADSBDemodGUI(); @@ -835,6 +840,7 @@ private: void updatePosition(Aircraft *aircraft); bool updateLocalPosition(Aircraft *aircraft, double latitude, double longitude, bool surfacePosition); void sendToMap(Aircraft *aircraft, QList *animations); + Aircraft *getAircraft(int icao, bool &newAircraft); void handleADSB( const QByteArray data, const QDateTime dateTime, @@ -884,6 +890,7 @@ private: void findOnChannelMap(Aircraft *aircraft); int grayToBinary(int gray, int bits) const; void redrawMap(); + void applyImportSettings(); void leaveEvent(QEvent*); void enterEvent(QEvent*); @@ -933,6 +940,8 @@ private slots: void photoClicked(); virtual void showEvent(QShowEvent *event); virtual bool eventFilter(QObject *obj, QEvent *event); + void import(); + void handleImportReply(QNetworkReply* reply); signals: void homePositionChanged(); diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.ui b/plugins/channelrx/demodadsb/adsbdemodgui.ui index f74220be9..aadb4abb3 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.ui +++ b/plugins/channelrx/demodadsb/adsbdemodgui.ui @@ -1336,6 +1336,7 @@ logEnable logFilename logOpen + findOnMapFeature devicesRefresh device adsbData diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp index 375d2cda1..5790fa66e 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp @@ -42,9 +42,22 @@ void ADSBDemodSettings::resetToDefaults() m_samplesPerBit = 4; m_removeTimeout = 60; m_feedEnabled = false; - m_feedHost = "feed.adsbexchange.com"; - m_feedPort = 30005; - m_feedFormat = BeastBinary; + m_exportClientEnabled = true; + m_exportClientHost = "feed.adsbexchange.com"; + m_exportClientPort = 30005; + m_exportClientFormat = BeastBinary; + m_exportServerEnabled = false; + m_exportServerPort = 30005; + m_importEnabled = false; + m_importHost = "opensky-network.org"; + m_importUsername = ""; + m_importPassword = ""; + m_importParameters = ""; + m_importPeriod = 10.0; + m_importMinLatitude = ""; + m_importMaxLatitude = ""; + m_importMinLongitude = ""; + m_importMaxLongitude = ""; m_rgbColor = QColor(244, 151, 57).rgb(); m_title = "ADS-B Demodulator"; m_streamIndex = 0; @@ -94,8 +107,8 @@ QByteArray ADSBDemodSettings::serialize() const s.writeS32(4, m_samplesPerBit); s.writeS32(5, m_removeTimeout); s.writeBool(6, m_feedEnabled); - s.writeString(7, m_feedHost); - s.writeU32(8, m_feedPort); + s.writeString(7, m_exportClientHost); + s.writeU32(8, m_exportClientPort); s.writeU32(9, m_rgbColor); if (m_channelMarker) { @@ -116,7 +129,7 @@ QByteArray ADSBDemodSettings::serialize() const s.writeBool(21, m_flightPaths); s.writeS32(22, m_deviceIndex); s.writeBool(23, m_siUnits); - s.writeS32(24, (int)m_feedFormat); + s.writeS32(24, (int)m_exportClientFormat); s.writeString(25, m_tableFontName); s.writeS32(26, m_tableFontSize); s.writeBool(27, m_displayDemodStats); @@ -146,6 +159,20 @@ QByteArray ADSBDemodSettings::serialize() const s.writeBool(44, m_verboseModelMatching); s.writeS32(45, m_airfieldElevation); + s.writeBool(46, m_exportClientEnabled); + s.writeBool(47, m_exportServerEnabled); + s.writeBool(48, m_exportServerPort); + s.writeBool(49, m_importEnabled); + s.writeString(50, m_importHost); + s.writeString(51, m_importUsername); + s.writeString(52, m_importPassword); + s.writeString(53, m_importParameters); + s.writeFloat(54, m_importPeriod); + s.writeString(55, m_importMinLatitude); + s.writeString(56, m_importMaxLatitude); + s.writeString(57, m_importMinLongitude); + s.writeString(58, m_importMaxLongitude); + for (int i = 0; i < ADSBDEMOD_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); } @@ -187,12 +214,12 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) d.readS32(4, &m_samplesPerBit, 4); d.readS32(5, &m_removeTimeout, 60); d.readBool(6, &m_feedEnabled, false); - d.readString(7, &m_feedHost, "feed.adsbexchange.com"); + d.readString(7, &m_exportClientHost, "feed.adsbexchange.com"); d.readU32(8, &utmp, 0); if ((utmp > 1023) && (utmp < 65535)) { - m_feedPort = utmp; + m_exportClientPort = utmp; } else { - m_feedPort = 30005; + m_exportClientPort = 30005; } d.readU32(9, &m_rgbColor, QColor(244, 151, 57).rgb()); @@ -219,7 +246,7 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) d.readBool(21, &m_flightPaths, true); d.readS32(22, &m_deviceIndex, -1); d.readBool(23, &m_siUnits, false); - d.readS32(24, (int *) &m_feedFormat, BeastBinary); + d.readS32(24, (int *) &m_exportClientFormat, BeastBinary); d.readString(25, &m_tableFontName, "Liberation Sans"); d.readS32(26, &m_tableFontSize, 9); d.readBool(27, &m_displayDemodStats, false); @@ -253,6 +280,25 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) d.readBool(44, &m_verboseModelMatching, false); d.readS32(45, &m_airfieldElevation, 0); + d.readBool(46, &m_exportClientEnabled, true); + d.readBool(47, &m_exportServerEnabled, true); + d.readU32(48, &utmp, 0); + if ((utmp > 1023) && (utmp < 65535)) { + m_exportServerPort = utmp; + } else { + m_exportServerPort = 30005; + } + d.readBool(49, &m_importEnabled, false); + d.readString(50, &m_importHost, "opensky-network.org"); + d.readString(51, &m_importUsername, ""); + d.readString(52, &m_importPassword, ""); + d.readString(53, &m_importParameters, ""); + d.readFloat(54, &m_importPeriod, 10.0f); + d.readString(55, &m_importMinLatitude, ""); + d.readString(56, &m_importMaxLatitude, ""); + d.readString(57, &m_importMinLongitude, ""); + d.readString(58, &m_importMaxLongitude, ""); + 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 86c21153d..88ae38cc4 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.h +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.h @@ -86,13 +86,27 @@ struct ADSBDemodSettings Real m_correlationThreshold; //!< Correlation power threshold in dB int m_samplesPerBit; int m_removeTimeout; //!< Time in seconds before removing an aircraft, unless a new frame is received + bool m_feedEnabled; - QString m_feedHost; - uint16_t m_feedPort; + bool m_exportClientEnabled; + QString m_exportClientHost; + uint16_t m_exportClientPort; enum FeedFormat { BeastBinary, BeastHex - } m_feedFormat; + } m_exportClientFormat; + bool m_exportServerEnabled; + uint16_t m_exportServerPort; + bool m_importEnabled; + QString m_importHost; + QString m_importUsername; + QString m_importPassword; + QString m_importParameters; + float m_importPeriod; + QString m_importMinLatitude; + QString m_importMaxLatitude; + QString m_importMinLongitude; + QString m_importMaxLongitude; quint32 m_rgbColor; QString m_title; diff --git a/plugins/channelrx/demodadsb/adsbdemodworker.cpp b/plugins/channelrx/demodadsb/adsbdemodworker.cpp index 8a66508d9..d03e1455f 100644 --- a/plugins/channelrx/demodadsb/adsbdemodworker.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodworker.cpp @@ -28,6 +28,57 @@ MESSAGE_CLASS_DEFINITION(ADSBDemodWorker::MsgConfigureADSBDemodWorker, Message) +ADSBBeastServer::ADSBBeastServer() +{ +} + +void ADSBBeastServer::listen(quint16 port) +{ + QTcpServer::listen(QHostAddress::Any, port); + qDebug() << "ADSBBeastServer listening on port " << serverPort(); +} + +void ADSBBeastServer::incomingConnection(qintptr socket) +{ + qDebug() << "ADSBBeastServer client connected"; + QTcpSocket *s = new QTcpSocket(this); + connect(s, &QTcpSocket::readyRead, this, &ADSBBeastServer::readClient); + connect(s, SIGNAL(disconnected()), this, SLOT(discardClient())); + s->setSocketDescriptor(socket); + m_clients.append(s); +} + +void ADSBBeastServer::send(const char *data, int length) +{ + // Send frame to all clients + for (auto client : m_clients) { + client->write(data, length); + } +} + +void ADSBBeastServer::close() +{ + for (auto client : m_clients) { + client->deleteLater(); + } + m_clients.clear(); + QTcpServer::close(); +} + +void ADSBBeastServer::readClient() +{ + QTcpSocket *socket = (QTcpSocket *)sender(); + socket->readAll(); +} + +void ADSBBeastServer::discardClient() +{ + qDebug() << "ADSBBeastServer client disconnected"; + QTcpSocket *socket = (QTcpSocket*)sender(); + socket->deleteLater(); + m_clients.removeAll(socket); +} + ADSBDemodWorker::ADSBDemodWorker() : m_running(false), m_mutex(QMutex::Recursive) @@ -41,6 +92,8 @@ ADSBDemodWorker::ADSBDemodWorker() : #else connect(&m_socket, &QAbstractSocket::errorOccurred, this, &ADSBDemodWorker::errorOccurred); #endif + m_startTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); + m_heartbeatTimer.start(60*1000); } ADSBDemodWorker::~ADSBDemodWorker() @@ -63,7 +116,6 @@ bool ADSBDemodWorker::startWork() } connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - m_heartbeatTimer.start(60*1000); m_running = true; return m_running; } @@ -76,7 +128,6 @@ void ADSBDemodWorker::stopWork() return; } - m_heartbeatTimer.stop(); disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); m_running = false; } @@ -119,23 +170,43 @@ void ADSBDemodWorker::applySettings(const ADSBDemodSettings& settings, bool forc { qDebug() << "ADSBDemodWorker::applySettings:" << " m_feedEnabled: " << settings.m_feedEnabled - << " m_feedHost: " << settings.m_feedHost - << " m_feedPort: " << settings.m_feedPort - << " m_feedFormat: " << settings.m_feedFormat + << " m_exportClientEnabled: " << settings.m_exportClientEnabled + << " m_exportClientHost: " << settings.m_exportClientHost + << " m_exportClientPort: " << settings.m_exportClientPort + << " m_exportClientFormat: " << settings.m_exportClientFormat + << " m_exportServerEnabled: " << settings.m_exportServerEnabled + << " m_exportServerPort: " << settings.m_exportServerPort << " m_logEnabled: " << settings.m_logEnabled << " m_logFilename: " << settings.m_logFilename << " force: " << force; if ((settings.m_feedEnabled != m_settings.m_feedEnabled) - || (settings.m_feedHost != m_settings.m_feedHost) - || (settings.m_feedPort != m_settings.m_feedPort) || force) + || (settings.m_exportClientEnabled != m_settings.m_exportClientEnabled) + || (settings.m_exportClientHost != m_settings.m_exportClientHost) + || (settings.m_exportClientPort != m_settings.m_exportClientPort) + || force) { // Close any existing connection - if (m_socket.isOpen()) + if (m_socket.isOpen()) { m_socket.close(); + } // Open connection - if (settings.m_feedEnabled) - m_socket.connectToHost(settings.m_feedHost, settings.m_feedPort); + if (settings.m_feedEnabled && settings.m_exportClientEnabled) { + m_socket.connectToHost(settings.m_exportClientHost, settings.m_exportClientPort); + } + } + + if ((settings.m_feedEnabled != m_settings.m_feedEnabled) + || (settings.m_exportServerEnabled != m_settings.m_exportServerEnabled) + || (settings.m_exportServerPort != m_settings.m_exportServerPort) + || force) + { + if (m_beastServer.isListening()) { + m_beastServer.close(); + } + if (settings.m_feedEnabled && settings.m_exportServerEnabled) { + m_beastServer.listen(settings.m_exportServerPort); + } } if ((settings.m_logEnabled != m_settings.m_logEnabled) @@ -173,7 +244,7 @@ void ADSBDemodWorker::applySettings(const ADSBDemodSettings& settings, bool forc void ADSBDemodWorker::connected() { - qDebug() << "ADSBDemodWorker::connected " << m_settings.m_feedHost; + qDebug() << "ADSBDemodWorker::connected " << m_settings.m_exportClientHost; } void ADSBDemodWorker::disconnected() @@ -195,11 +266,12 @@ void ADSBDemodWorker::recv() void ADSBDemodWorker::send(const char *data, int length) { - if (m_settings.m_feedEnabled) + if (m_settings.m_feedEnabled && m_settings.m_exportClientEnabled) { // Reopen connection if it was lost - if (!m_socket.isOpen()) - m_socket.connectToHost(m_settings.m_feedHost, m_settings.m_feedPort); + if (!m_socket.isOpen()) { + m_socket.connectToHost(m_settings.m_exportClientHost, m_settings.m_exportClientPort); + } // Send data m_socket.write(data, length); } @@ -210,8 +282,9 @@ void ADSBDemodWorker::send(const char *data, int length) char *ADSBDemodWorker::escape(char *p, char c) { *p++ = c; - if (c == BEAST_ESC) + if (c == BEAST_ESC) { *p++ = BEAST_ESC; + } return p; } @@ -220,13 +293,14 @@ char *ADSBDemodWorker::escape(char *p, char c) // Log to .csv file void ADSBDemodWorker::handleADSB(QByteArray data, const QDateTime dateTime, float correlation) { - if (m_logFile.isOpen()) - { + if (m_logFile.isOpen()) { m_logStream << dateTime.date().toString() << "," << dateTime.time().toString() << "," << data.toHex() << "," << correlation << "\n"; } - if (m_settings.m_feedEnabled) + + if (m_settings.m_feedEnabled && (m_settings.m_exportClientEnabled || m_settings.m_exportServerEnabled)) { - if (m_settings.m_feedFormat == ADSBDemodSettings::BeastBinary) + if ((m_settings.m_exportClientEnabled && (m_settings.m_exportClientFormat == ADSBDemodSettings::BeastBinary)) + || m_settings.m_exportServerEnabled) { char beastBinary[2+6*2+1*2+14*2]; int length; @@ -234,20 +308,21 @@ void ADSBDemodWorker::handleADSB(QByteArray data, const QDateTime dateTime, floa qint64 timestamp; unsigned char signalStrength; - timestamp = dateTime.toMSecsSinceEpoch(); + // Timestamp seems to be 12MHz ticks since device started + timestamp = (dateTime.toMSecsSinceEpoch() - m_startTime) * 12000; - if (correlation > 255) + if (correlation > 255) { signalStrength = 255; - if (correlation < 1) + } else if (correlation < 1) { signalStrength = 1; - else + } else { signalStrength = (unsigned char)correlation; + } *p++ = BEAST_ESC; *p++ = '3'; // Mode-S long - p = escape(p, timestamp >> 56); // Big-endian timestamp - p = escape(p, timestamp >> 48); + p = escape(p, timestamp >> 48); // Big-endian timestamp p = escape(p, timestamp >> 32); p = escape(p, timestamp >> 24); p = escape(p, timestamp >> 16); @@ -256,14 +331,20 @@ void ADSBDemodWorker::handleADSB(QByteArray data, const QDateTime dateTime, floa p = escape(p, signalStrength); // Signal strength - for (int i = 0; i < data.length(); i++) // ADS-B data + for (int i = 0; i < data.length(); i++) { // ADS-B data p = escape(p, data[i]); + } length = p - beastBinary; - send(beastBinary, length); + if ((m_settings.m_exportClientEnabled) && (m_settings.m_exportClientFormat == ADSBDemodSettings::BeastBinary)) { + send(beastBinary, length); + } + if (m_settings.m_exportServerEnabled) { + m_beastServer.send(beastBinary, length); + } } - else if (m_settings.m_feedFormat == ADSBDemodSettings::BeastHex) + if (m_settings.m_exportClientEnabled && (m_settings.m_exportClientFormat == ADSBDemodSettings::BeastHex)) { QString beastHex = "*" + data.toHex() + ";\n"; send(beastHex.toUtf8(), beastHex.size()); @@ -274,6 +355,14 @@ void ADSBDemodWorker::handleADSB(QByteArray data, const QDateTime dateTime, floa // Periodically send heartbeat to keep connection alive void ADSBDemodWorker::heartbeat() { - const char heartbeat[] = {BEAST_ESC, '1', 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Mode AC packet - send(heartbeat, sizeof(heartbeat)); + if (m_running) + { + const char heartbeat[] = {BEAST_ESC, '1', 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Mode AC packet + if (m_settings.m_exportClientEnabled) { + send(heartbeat, sizeof(heartbeat)); + } + if (m_settings.m_exportServerEnabled) { + m_beastServer.send(heartbeat, sizeof(heartbeat)); + } + } } diff --git a/plugins/channelrx/demodadsb/adsbdemodworker.h b/plugins/channelrx/demodadsb/adsbdemodworker.h index b60b122be..858b4fa11 100644 --- a/plugins/channelrx/demodadsb/adsbdemodworker.h +++ b/plugins/channelrx/demodadsb/adsbdemodworker.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,27 @@ #include "adsbdemodsettings.h" +// Beast binary server for sending ADS-B data to OpenSky Network (and others) +class ADSBBeastServer : public QTcpServer +{ + Q_OBJECT + +private: + QList m_clients; + +public: + ADSBBeastServer(); + void listen(quint16 port = 30005); + void incomingConnection(qintptr socket); + void send(const char *data, int length); + void close(); + +private slots: + void readClient(); + void discardClient(); +}; + +// Worker that forwards ADS-B frames to various aggregators class ADSBDemodWorker : public QObject { Q_OBJECT @@ -75,6 +97,8 @@ private: QTcpSocket m_socket; QFile m_logFile; QTextStream m_logStream; + qint64 m_startTime; + ADSBBeastServer m_beastServer; bool handleMessage(const Message& cmd); void applySettings(const ADSBDemodSettings& settings, bool force = false); diff --git a/plugins/channelrx/demodadsb/readme.md b/plugins/channelrx/demodadsb/readme.md index 5feb3ef2e..54e2de187 100644 --- a/plugins/channelrx/demodadsb/readme.md +++ b/plugins/channelrx/demodadsb/readme.md @@ -106,16 +106,26 @@ To use this feature, an [aviationstack](https://aviationstack.com) API Key must

16: Feed

-Checking Feed enables feeding received ADS-B frames to aggregators such as ADS-B Exchange: https://www.adsbexchange.com or ADSBHub -: https://www.adsbhub.org. Right clicking on the Feed button opens the Feed Settings dialog. +Checking Feed enables feeding received ADS-B frames to aggregators such as [ADS-B Exchange](https://www.adsbexchange.com), [ADSBHub](https://www.adsbhub.org) or [OpenSky Network](https://opensky-network.org/) +and receiving aircraft state from anywhere in the world from [OpenSky Network](https://opensky-network.org/). Right clicking on the Feed button opens the Feed Settings dialog. -The server hostname and port to send the frames to should be entered in the Server and Port fields, with the appropriate format selected: +The ADS-B plugin can export ADS-B frames acting as both a client and server. When a client, the ADS-B plugin opens a connection to a remote host. When a server, the remote computer connects to this computer. -* For ADS-B Exchange, set Server hostname to feed.adsbexchange.com, Port to 30005 and Format to Beast binary. You can check for successful feeding (after about 30 seconds) at: https://www.adsbexchange.com/myip/ -* For ADSBHub, set Server hostname to data.adsbhub.org, Port to 5002 and Format to Beast hex. You will need to have setup an account on ADSBHub first. You can check for successful feeding at: https://www.adsbhub.org/statistic.php +As a client: + +* For ADS-B Exchange, check Enable Client, set Server hostname to feed.adsbexchange.com, Port to 30005 and Format to Beast binary. You can check for successful feeding (after about 30 seconds) at: https://www.adsbexchange.com/myip/ +* For ADSBHub, check Enable Client, set Server hostname to data.adsbhub.org, Port to 5002 and Format to Beast hex. You will need to have setup an account on ADSBHub first. You can check for successful feeding at: https://www.adsbhub.org/statistic.php + +As a server: + +* For OpenSky Network, check Enable Server and set Port to 30005. You can check for successfull feeding at: https://opensky-network.org/my-opensky The Beast binary and Hex formats are as detailed here: https://wiki.jetvision.de/wiki/Mode-S_Beast:Data_Output_Formats +When Enable import is checked, aircraft data for aircraft anywhere in the world can be imported from OpenSky Network. +A username and password are not required, but when specified, this allows the update period to be reduced to 5 seconds instead of 10 seconds. +To limit network traffic and processing power requirements, a geographical region can be set via the mininum and maximum latitude and longitude fields. +

17: Open Notifications Dialog

When clicked, opens the Notifications Dialog, which allows speech notifications or programs/scripts to be run when aircraft matching user-defined rules are seen. diff --git a/swagger/sdrangel/api/swagger/include/ADSBDemod.yaml b/swagger/sdrangel/api/swagger/include/ADSBDemod.yaml index 14d7690d8..da23a93f3 100644 --- a/swagger/sdrangel/api/swagger/include/ADSBDemod.yaml +++ b/swagger/sdrangel/api/swagger/include/ADSBDemod.yaml @@ -35,22 +35,50 @@ ADSBDemodSettings: description: Number of taps per phase in channel interpolator removeTimeout: type: integer - beastEnabled: + feedEnabled: + type: integer + exportClientEnabled: type: integer description: > - Send data to beast server + Send data to server * 0 - Do not send data * 1 - Send data - beastHost: + exportClientHost: + description: Host to send data to type: string - beastPort: + exportClientPort: type: integer - feedFormat: + exportClientFormat: type: integer description: > Format of sent data * 0 - Beast binary - * 1 - Beast index + * 1 - Beast hex + exportServerEnabled: + type: integer + exportServerPort: + type: integer + importEnabled: + type: integer + importHost: + type: string + importUsername: + type: string + importPassword: + type: string + importParameters: + type: string + importPeriod: + type: number + format: float + importMinLatitude: + type: string + importMaxLatitude: + type: string + importMinLongitude: + type: string + importMaxLongitude: + type: string logFilename: type: string logEnabled: diff --git a/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.cpp index 9b85b35a1..882ebd9a2 100644 --- a/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.cpp @@ -46,14 +46,40 @@ SWGADSBDemodSettings::SWGADSBDemodSettings() { m_interpolator_taps_per_phase_isSet = false; remove_timeout = 0; m_remove_timeout_isSet = false; - beast_enabled = 0; - m_beast_enabled_isSet = false; - beast_host = nullptr; - m_beast_host_isSet = false; - beast_port = 0; - m_beast_port_isSet = false; - feed_format = 0; - m_feed_format_isSet = false; + feed_enabled = 0; + m_feed_enabled_isSet = false; + export_client_enabled = 0; + m_export_client_enabled_isSet = false; + export_client_host = nullptr; + m_export_client_host_isSet = false; + export_client_port = 0; + m_export_client_port_isSet = false; + export_client_format = 0; + m_export_client_format_isSet = false; + export_server_enabled = 0; + m_export_server_enabled_isSet = false; + export_server_port = 0; + m_export_server_port_isSet = false; + import_enabled = 0; + m_import_enabled_isSet = false; + import_host = nullptr; + m_import_host_isSet = false; + import_username = nullptr; + m_import_username_isSet = false; + import_password = nullptr; + m_import_password_isSet = false; + import_parameters = nullptr; + m_import_parameters_isSet = false; + import_period = 0.0f; + m_import_period_isSet = false; + import_min_latitude = nullptr; + m_import_min_latitude_isSet = false; + import_max_latitude = nullptr; + m_import_max_latitude_isSet = false; + import_min_longitude = nullptr; + m_import_min_longitude_isSet = false; + import_max_longitude = nullptr; + m_import_max_longitude_isSet = false; log_filename = nullptr; m_log_filename_isSet = false; log_enabled = 0; @@ -104,14 +130,40 @@ SWGADSBDemodSettings::init() { m_interpolator_taps_per_phase_isSet = false; remove_timeout = 0; m_remove_timeout_isSet = false; - beast_enabled = 0; - m_beast_enabled_isSet = false; - beast_host = new QString(""); - m_beast_host_isSet = false; - beast_port = 0; - m_beast_port_isSet = false; - feed_format = 0; - m_feed_format_isSet = false; + feed_enabled = 0; + m_feed_enabled_isSet = false; + export_client_enabled = 0; + m_export_client_enabled_isSet = false; + export_client_host = new QString(""); + m_export_client_host_isSet = false; + export_client_port = 0; + m_export_client_port_isSet = false; + export_client_format = 0; + m_export_client_format_isSet = false; + export_server_enabled = 0; + m_export_server_enabled_isSet = false; + export_server_port = 0; + m_export_server_port_isSet = false; + import_enabled = 0; + m_import_enabled_isSet = false; + import_host = new QString(""); + m_import_host_isSet = false; + import_username = new QString(""); + m_import_username_isSet = false; + import_password = new QString(""); + m_import_password_isSet = false; + import_parameters = new QString(""); + m_import_parameters_isSet = false; + import_period = 0.0f; + m_import_period_isSet = false; + import_min_latitude = new QString(""); + m_import_min_latitude_isSet = false; + import_max_latitude = new QString(""); + m_import_max_latitude_isSet = false; + import_min_longitude = new QString(""); + m_import_min_longitude_isSet = false; + import_max_longitude = new QString(""); + m_import_max_longitude_isSet = false; log_filename = new QString(""); m_log_filename_isSet = false; log_enabled = 0; @@ -150,11 +202,40 @@ SWGADSBDemodSettings::cleanup() { - if(beast_host != nullptr) { - delete beast_host; + + if(export_client_host != nullptr) { + delete export_client_host; } + + + + if(import_host != nullptr) { + delete import_host; + } + if(import_username != nullptr) { + delete import_username; + } + if(import_password != nullptr) { + delete import_password; + } + if(import_parameters != nullptr) { + delete import_parameters; + } + + if(import_min_latitude != nullptr) { + delete import_min_latitude; + } + if(import_max_latitude != nullptr) { + delete import_max_latitude; + } + if(import_min_longitude != nullptr) { + delete import_min_longitude; + } + if(import_max_longitude != nullptr) { + delete import_max_longitude; + } if(log_filename != nullptr) { delete log_filename; } @@ -208,13 +289,39 @@ SWGADSBDemodSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&remove_timeout, pJson["removeTimeout"], "qint32", ""); - ::SWGSDRangel::setValue(&beast_enabled, pJson["beastEnabled"], "qint32", ""); + ::SWGSDRangel::setValue(&feed_enabled, pJson["feedEnabled"], "qint32", ""); - ::SWGSDRangel::setValue(&beast_host, pJson["beastHost"], "QString", "QString"); + ::SWGSDRangel::setValue(&export_client_enabled, pJson["exportClientEnabled"], "qint32", ""); - ::SWGSDRangel::setValue(&beast_port, pJson["beastPort"], "qint32", ""); + ::SWGSDRangel::setValue(&export_client_host, pJson["exportClientHost"], "QString", "QString"); - ::SWGSDRangel::setValue(&feed_format, pJson["feedFormat"], "qint32", ""); + ::SWGSDRangel::setValue(&export_client_port, pJson["exportClientPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&export_client_format, pJson["exportClientFormat"], "qint32", ""); + + ::SWGSDRangel::setValue(&export_server_enabled, pJson["exportServerEnabled"], "qint32", ""); + + ::SWGSDRangel::setValue(&export_server_port, pJson["exportServerPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&import_enabled, pJson["importEnabled"], "qint32", ""); + + ::SWGSDRangel::setValue(&import_host, pJson["importHost"], "QString", "QString"); + + ::SWGSDRangel::setValue(&import_username, pJson["importUsername"], "QString", "QString"); + + ::SWGSDRangel::setValue(&import_password, pJson["importPassword"], "QString", "QString"); + + ::SWGSDRangel::setValue(&import_parameters, pJson["importParameters"], "QString", "QString"); + + ::SWGSDRangel::setValue(&import_period, pJson["importPeriod"], "float", ""); + + ::SWGSDRangel::setValue(&import_min_latitude, pJson["importMinLatitude"], "QString", "QString"); + + ::SWGSDRangel::setValue(&import_max_latitude, pJson["importMaxLatitude"], "QString", "QString"); + + ::SWGSDRangel::setValue(&import_min_longitude, pJson["importMinLongitude"], "QString", "QString"); + + ::SWGSDRangel::setValue(&import_max_longitude, pJson["importMaxLongitude"], "QString", "QString"); ::SWGSDRangel::setValue(&log_filename, pJson["logFilename"], "QString", "QString"); @@ -283,17 +390,56 @@ SWGADSBDemodSettings::asJsonObject() { if(m_remove_timeout_isSet){ obj->insert("removeTimeout", QJsonValue(remove_timeout)); } - if(m_beast_enabled_isSet){ - obj->insert("beastEnabled", QJsonValue(beast_enabled)); + if(m_feed_enabled_isSet){ + obj->insert("feedEnabled", QJsonValue(feed_enabled)); } - if(beast_host != nullptr && *beast_host != QString("")){ - toJsonValue(QString("beastHost"), beast_host, obj, QString("QString")); + if(m_export_client_enabled_isSet){ + obj->insert("exportClientEnabled", QJsonValue(export_client_enabled)); } - if(m_beast_port_isSet){ - obj->insert("beastPort", QJsonValue(beast_port)); + if(export_client_host != nullptr && *export_client_host != QString("")){ + toJsonValue(QString("exportClientHost"), export_client_host, obj, QString("QString")); } - if(m_feed_format_isSet){ - obj->insert("feedFormat", QJsonValue(feed_format)); + if(m_export_client_port_isSet){ + obj->insert("exportClientPort", QJsonValue(export_client_port)); + } + if(m_export_client_format_isSet){ + obj->insert("exportClientFormat", QJsonValue(export_client_format)); + } + if(m_export_server_enabled_isSet){ + obj->insert("exportServerEnabled", QJsonValue(export_server_enabled)); + } + if(m_export_server_port_isSet){ + obj->insert("exportServerPort", QJsonValue(export_server_port)); + } + if(m_import_enabled_isSet){ + obj->insert("importEnabled", QJsonValue(import_enabled)); + } + if(import_host != nullptr && *import_host != QString("")){ + toJsonValue(QString("importHost"), import_host, obj, QString("QString")); + } + if(import_username != nullptr && *import_username != QString("")){ + toJsonValue(QString("importUsername"), import_username, obj, QString("QString")); + } + if(import_password != nullptr && *import_password != QString("")){ + toJsonValue(QString("importPassword"), import_password, obj, QString("QString")); + } + if(import_parameters != nullptr && *import_parameters != QString("")){ + toJsonValue(QString("importParameters"), import_parameters, obj, QString("QString")); + } + if(m_import_period_isSet){ + obj->insert("importPeriod", QJsonValue(import_period)); + } + if(import_min_latitude != nullptr && *import_min_latitude != QString("")){ + toJsonValue(QString("importMinLatitude"), import_min_latitude, obj, QString("QString")); + } + if(import_max_latitude != nullptr && *import_max_latitude != QString("")){ + toJsonValue(QString("importMaxLatitude"), import_max_latitude, obj, QString("QString")); + } + if(import_min_longitude != nullptr && *import_min_longitude != QString("")){ + toJsonValue(QString("importMinLongitude"), import_min_longitude, obj, QString("QString")); + } + if(import_max_longitude != nullptr && *import_max_longitude != QString("")){ + toJsonValue(QString("importMaxLongitude"), import_max_longitude, obj, QString("QString")); } if(log_filename != nullptr && *log_filename != QString("")){ toJsonValue(QString("logFilename"), log_filename, obj, QString("QString")); @@ -426,43 +572,173 @@ SWGADSBDemodSettings::setRemoveTimeout(qint32 remove_timeout) { } qint32 -SWGADSBDemodSettings::getBeastEnabled() { - return beast_enabled; +SWGADSBDemodSettings::getFeedEnabled() { + return feed_enabled; } void -SWGADSBDemodSettings::setBeastEnabled(qint32 beast_enabled) { - this->beast_enabled = beast_enabled; - this->m_beast_enabled_isSet = true; +SWGADSBDemodSettings::setFeedEnabled(qint32 feed_enabled) { + this->feed_enabled = feed_enabled; + this->m_feed_enabled_isSet = true; +} + +qint32 +SWGADSBDemodSettings::getExportClientEnabled() { + return export_client_enabled; +} +void +SWGADSBDemodSettings::setExportClientEnabled(qint32 export_client_enabled) { + this->export_client_enabled = export_client_enabled; + this->m_export_client_enabled_isSet = true; } QString* -SWGADSBDemodSettings::getBeastHost() { - return beast_host; +SWGADSBDemodSettings::getExportClientHost() { + return export_client_host; } void -SWGADSBDemodSettings::setBeastHost(QString* beast_host) { - this->beast_host = beast_host; - this->m_beast_host_isSet = true; +SWGADSBDemodSettings::setExportClientHost(QString* export_client_host) { + this->export_client_host = export_client_host; + this->m_export_client_host_isSet = true; } qint32 -SWGADSBDemodSettings::getBeastPort() { - return beast_port; +SWGADSBDemodSettings::getExportClientPort() { + return export_client_port; } void -SWGADSBDemodSettings::setBeastPort(qint32 beast_port) { - this->beast_port = beast_port; - this->m_beast_port_isSet = true; +SWGADSBDemodSettings::setExportClientPort(qint32 export_client_port) { + this->export_client_port = export_client_port; + this->m_export_client_port_isSet = true; } qint32 -SWGADSBDemodSettings::getFeedFormat() { - return feed_format; +SWGADSBDemodSettings::getExportClientFormat() { + return export_client_format; } void -SWGADSBDemodSettings::setFeedFormat(qint32 feed_format) { - this->feed_format = feed_format; - this->m_feed_format_isSet = true; +SWGADSBDemodSettings::setExportClientFormat(qint32 export_client_format) { + this->export_client_format = export_client_format; + this->m_export_client_format_isSet = true; +} + +qint32 +SWGADSBDemodSettings::getExportServerEnabled() { + return export_server_enabled; +} +void +SWGADSBDemodSettings::setExportServerEnabled(qint32 export_server_enabled) { + this->export_server_enabled = export_server_enabled; + this->m_export_server_enabled_isSet = true; +} + +qint32 +SWGADSBDemodSettings::getExportServerPort() { + return export_server_port; +} +void +SWGADSBDemodSettings::setExportServerPort(qint32 export_server_port) { + this->export_server_port = export_server_port; + this->m_export_server_port_isSet = true; +} + +qint32 +SWGADSBDemodSettings::getImportEnabled() { + return import_enabled; +} +void +SWGADSBDemodSettings::setImportEnabled(qint32 import_enabled) { + this->import_enabled = import_enabled; + this->m_import_enabled_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportHost() { + return import_host; +} +void +SWGADSBDemodSettings::setImportHost(QString* import_host) { + this->import_host = import_host; + this->m_import_host_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportUsername() { + return import_username; +} +void +SWGADSBDemodSettings::setImportUsername(QString* import_username) { + this->import_username = import_username; + this->m_import_username_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportPassword() { + return import_password; +} +void +SWGADSBDemodSettings::setImportPassword(QString* import_password) { + this->import_password = import_password; + this->m_import_password_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportParameters() { + return import_parameters; +} +void +SWGADSBDemodSettings::setImportParameters(QString* import_parameters) { + this->import_parameters = import_parameters; + this->m_import_parameters_isSet = true; +} + +float +SWGADSBDemodSettings::getImportPeriod() { + return import_period; +} +void +SWGADSBDemodSettings::setImportPeriod(float import_period) { + this->import_period = import_period; + this->m_import_period_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportMinLatitude() { + return import_min_latitude; +} +void +SWGADSBDemodSettings::setImportMinLatitude(QString* import_min_latitude) { + this->import_min_latitude = import_min_latitude; + this->m_import_min_latitude_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportMaxLatitude() { + return import_max_latitude; +} +void +SWGADSBDemodSettings::setImportMaxLatitude(QString* import_max_latitude) { + this->import_max_latitude = import_max_latitude; + this->m_import_max_latitude_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportMinLongitude() { + return import_min_longitude; +} +void +SWGADSBDemodSettings::setImportMinLongitude(QString* import_min_longitude) { + this->import_min_longitude = import_min_longitude; + this->m_import_min_longitude_isSet = true; +} + +QString* +SWGADSBDemodSettings::getImportMaxLongitude() { + return import_max_longitude; +} +void +SWGADSBDemodSettings::setImportMaxLongitude(QString* import_max_longitude) { + this->import_max_longitude = import_max_longitude; + this->m_import_max_longitude_isSet = true; } QString* @@ -617,16 +893,55 @@ SWGADSBDemodSettings::isSet(){ if(m_remove_timeout_isSet){ isObjectUpdated = true; break; } - if(m_beast_enabled_isSet){ + if(m_feed_enabled_isSet){ isObjectUpdated = true; break; } - if(beast_host && *beast_host != QString("")){ + if(m_export_client_enabled_isSet){ isObjectUpdated = true; break; } - if(m_beast_port_isSet){ + if(export_client_host && *export_client_host != QString("")){ isObjectUpdated = true; break; } - if(m_feed_format_isSet){ + if(m_export_client_port_isSet){ + isObjectUpdated = true; break; + } + if(m_export_client_format_isSet){ + isObjectUpdated = true; break; + } + if(m_export_server_enabled_isSet){ + isObjectUpdated = true; break; + } + if(m_export_server_port_isSet){ + isObjectUpdated = true; break; + } + if(m_import_enabled_isSet){ + isObjectUpdated = true; break; + } + if(import_host && *import_host != QString("")){ + isObjectUpdated = true; break; + } + if(import_username && *import_username != QString("")){ + isObjectUpdated = true; break; + } + if(import_password && *import_password != QString("")){ + isObjectUpdated = true; break; + } + if(import_parameters && *import_parameters != QString("")){ + isObjectUpdated = true; break; + } + if(m_import_period_isSet){ + isObjectUpdated = true; break; + } + if(import_min_latitude && *import_min_latitude != QString("")){ + isObjectUpdated = true; break; + } + if(import_max_latitude && *import_max_latitude != QString("")){ + isObjectUpdated = true; break; + } + if(import_min_longitude && *import_min_longitude != QString("")){ + isObjectUpdated = true; break; + } + if(import_max_longitude && *import_max_longitude != QString("")){ isObjectUpdated = true; break; } if(log_filename && *log_filename != QString("")){ diff --git a/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.h b/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.h index a87aac050..fc141c3a6 100644 --- a/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGADSBDemodSettings.h @@ -71,17 +71,56 @@ public: qint32 getRemoveTimeout(); void setRemoveTimeout(qint32 remove_timeout); - qint32 getBeastEnabled(); - void setBeastEnabled(qint32 beast_enabled); + qint32 getFeedEnabled(); + void setFeedEnabled(qint32 feed_enabled); - QString* getBeastHost(); - void setBeastHost(QString* beast_host); + qint32 getExportClientEnabled(); + void setExportClientEnabled(qint32 export_client_enabled); - qint32 getBeastPort(); - void setBeastPort(qint32 beast_port); + QString* getExportClientHost(); + void setExportClientHost(QString* export_client_host); - qint32 getFeedFormat(); - void setFeedFormat(qint32 feed_format); + qint32 getExportClientPort(); + void setExportClientPort(qint32 export_client_port); + + qint32 getExportClientFormat(); + void setExportClientFormat(qint32 export_client_format); + + qint32 getExportServerEnabled(); + void setExportServerEnabled(qint32 export_server_enabled); + + qint32 getExportServerPort(); + void setExportServerPort(qint32 export_server_port); + + qint32 getImportEnabled(); + void setImportEnabled(qint32 import_enabled); + + QString* getImportHost(); + void setImportHost(QString* import_host); + + QString* getImportUsername(); + void setImportUsername(QString* import_username); + + QString* getImportPassword(); + void setImportPassword(QString* import_password); + + QString* getImportParameters(); + void setImportParameters(QString* import_parameters); + + float getImportPeriod(); + void setImportPeriod(float import_period); + + QString* getImportMinLatitude(); + void setImportMinLatitude(QString* import_min_latitude); + + QString* getImportMaxLatitude(); + void setImportMaxLatitude(QString* import_max_latitude); + + QString* getImportMinLongitude(); + void setImportMinLongitude(QString* import_min_longitude); + + QString* getImportMaxLongitude(); + void setImportMaxLongitude(QString* import_max_longitude); QString* getLogFilename(); void setLogFilename(QString* log_filename); @@ -150,17 +189,56 @@ private: qint32 remove_timeout; bool m_remove_timeout_isSet; - qint32 beast_enabled; - bool m_beast_enabled_isSet; + qint32 feed_enabled; + bool m_feed_enabled_isSet; - QString* beast_host; - bool m_beast_host_isSet; + qint32 export_client_enabled; + bool m_export_client_enabled_isSet; - qint32 beast_port; - bool m_beast_port_isSet; + QString* export_client_host; + bool m_export_client_host_isSet; - qint32 feed_format; - bool m_feed_format_isSet; + qint32 export_client_port; + bool m_export_client_port_isSet; + + qint32 export_client_format; + bool m_export_client_format_isSet; + + qint32 export_server_enabled; + bool m_export_server_enabled_isSet; + + qint32 export_server_port; + bool m_export_server_port_isSet; + + qint32 import_enabled; + bool m_import_enabled_isSet; + + QString* import_host; + bool m_import_host_isSet; + + QString* import_username; + bool m_import_username_isSet; + + QString* import_password; + bool m_import_password_isSet; + + QString* import_parameters; + bool m_import_parameters_isSet; + + float import_period; + bool m_import_period_isSet; + + QString* import_min_latitude; + bool m_import_min_latitude_isSet; + + QString* import_max_latitude; + bool m_import_max_latitude_isSet; + + QString* import_min_longitude; + bool m_import_min_longitude_isSet; + + QString* import_max_longitude; + bool m_import_max_longitude_isSet; QString* log_filename; bool m_log_filename_isSet;