1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-22 08:04:49 -05:00

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.
This commit is contained in:
Jon Beniston 2022-02-09 16:36:09 +00:00
parent e4b9bc7680
commit 267ae13534
15 changed files with 1641 additions and 395 deletions

View File

@ -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<QString>& 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));

View File

@ -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);
}
}

View File

@ -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;

View File

@ -6,13 +6,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>351</width>
<height>138</height>
<width>472</width>
<height>553</height>
</rect>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
@ -23,75 +22,334 @@
<item>
<widget class="QGroupBox" name="groupBox">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="hostLabel">
<property name="text">
<string>Server hostname</string>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="importSettings">
<property name="title">
<string>Import</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0">
<widget class="QLabel" name="importParametersLabel">
<property name="text">
<string>Parameters</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="importUsername">
<property name="toolTip">
<string>Username to access server with</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="latitudeMinLabel">
<property name="text">
<string>Latitude Min</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="latitudeMin">
<property name="toolTip">
<string>Minimum latitude of area to receive aircraft data from</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="latitudeMaxLabel">
<property name="text">
<string>Latitude Max</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="latitudeMax">
<property name="toolTip">
<string>Maximum latitude of area to receive aircraft data from</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="longitudeMinLabel">
<property name="toolTip">
<string>Minimum longitude of area to receive aircraft data from</string>
</property>
<property name="text">
<string>Longitude Min</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="longitudeMin"/>
</item>
<item row="1" column="2">
<widget class="QLabel" name="longitudeMaxLabel">
<property name="text">
<string>Longitude Max</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="longitudeMax">
<property name="toolTip">
<string>Maximum longitude of area to receive aircraft data from</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="importHostnameLabel">
<property name="text">
<string>Server hostname</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="importUsernameLabel">
<property name="text">
<string>Username</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="importPeriodLabel">
<property name="text">
<string>Update period (s)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="importEnabled">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="importEnabledLabel">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Enable import</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="importPassword">
<property name="toolTip">
<string>Password to access the server with</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="importParameters">
<property name="toolTip">
<string>Parameters for the API call such as geographic location</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="importPeriod">
<property name="toolTip">
<string>Time period in seconds between updates requested from the server</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>5.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="importHost">
<property name="toolTip">
<string>Hostname of server to receive ADS-B data from</string>
</property>
<item>
<property name="text">
<string>opensky-network.org</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="importPasswordLabel">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="portLabel">
<property name="text">
<string>Port number</string>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="exportClientSettings">
<property name="title">
<string>Export Client</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="exportClientEnabledLabel">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Enable client</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="exportClientEnabled">
<property name="toolTip">
<string>Enable TCP client</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="exportClientHostLabel">
<property name="text">
<string>Server hostname</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="exportClientHost">
<property name="toolTip">
<string>Hostname of server to feed ADS-B data to</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>feed.adsbexchange.com</string>
</property>
</item>
<item>
<property name="text">
<string>data.adsbhub.org</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="exportClientPortLabel">
<property name="text">
<string>Port</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="exportClientPort">
<property name="toolTip">
<string>The TCP port number the server is listening on</string>
</property>
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="exportClientFormatLabel">
<property name="text">
<string>Format</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="exportClientFormat">
<property name="toolTip">
<string>Format to feed the data to the server in</string>
</property>
<item>
<property name="text">
<string>Beast binary</string>
</property>
</item>
<item>
<property name="text">
<string>Beast hex</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="port">
<property name="toolTip">
<string>The TCP port number the server is listening on</string>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="exportServerSettings">
<property name="title">
<string>Export Server</string>
</property>
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="format">
<property name="toolTip">
<string>Format to feed the data to the server in</string>
</property>
<item>
<property name="text">
<string>Beast binary</string>
</property>
</item>
<item>
<property name="text">
<string>Beast hex</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="formatLabel">
<property name="text">
<string>Format</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="host">
<property name="toolTip">
<string>Hostname of server to feed ADS-B data to</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>feed.adsbexchange.com</string>
</property>
</item>
<item>
<property name="text">
<string>data.adsbhub.org</string>
</property>
</item>
<layout class="QFormLayout" name="formLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="exportServerPortLabel">
<property name="text">
<string>Port</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="exportServerPort">
<property name="toolTip">
<string>TCP port number to listen for connections on</string>
</property>
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="exportServerEnabledLabel">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Enable server</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="exportServerEnabled">
<property name="toolTip">
<string>Enable TCP server</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
@ -110,7 +368,22 @@
</layout>
</widget>
<tabstops>
<tabstop>port</tabstop>
<tabstop>exportClientEnabled</tabstop>
<tabstop>exportClientHost</tabstop>
<tabstop>exportClientPort</tabstop>
<tabstop>exportClientFormat</tabstop>
<tabstop>exportServerEnabled</tabstop>
<tabstop>exportServerPort</tabstop>
<tabstop>importEnabled</tabstop>
<tabstop>importHost</tabstop>
<tabstop>importUsername</tabstop>
<tabstop>importPassword</tabstop>
<tabstop>importParameters</tabstop>
<tabstop>importPeriod</tabstop>
<tabstop>latitudeMin</tabstop>
<tabstop>latitudeMax</tabstop>
<tabstop>longitudeMin</tabstop>
<tabstop>longitudeMax</tabstop>
</tabstops>
<resources/>
<connections>

View File

@ -32,6 +32,8 @@
#include <QClipboard>
#include <QFileDialog>
#include <QQmlProperty>
#include <QJsonDocument>
#include <QJsonObject>
#include <QtGui/private/qzipreader_p.h>
@ -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<QSize> 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<SWGSDRangel::SWGMapAnimation *> *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();
}
}

View File

@ -27,6 +27,7 @@
#include <QProgressDialog>
#include <QTextToSpeech>
#include <QRandomGenerator>
#include <QNetworkAccessManager>
#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<QString, float> m_modelAltitudeOffset;
QHash<QString, float> 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<SWGSDRangel::SWGMapAnimation *> *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();

View File

@ -1336,6 +1336,7 @@
<tabstop>logEnable</tabstop>
<tabstop>logFilename</tabstop>
<tabstop>logOpen</tabstop>
<tabstop>findOnMapFeature</tabstop>
<tabstop>devicesRefresh</tabstop>
<tabstop>device</tabstop>
<tabstop>adsbData</tabstop>

View File

@ -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);
}

View File

@ -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;

View File

@ -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));
}
}
}

View File

@ -21,6 +21,7 @@
#include <QObject>
#include <QTimer>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QTextStream>
@ -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<QTcpSocket*> 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);

View File

@ -106,16 +106,26 @@ To use this feature, an [aviationstack](https://aviationstack.com) API Key must
<h3>16: Feed</h3>
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.
<h3>17: Open Notifications Dialog</h3>
When clicked, opens the Notifications Dialog, which allows speech notifications or programs/scripts to be run when aircraft matching user-defined rules are seen.

View File

@ -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:

View File

@ -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("")){

View File

@ -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;