mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-21 23:55:13 -05:00
Compare commits
3 Commits
2292860f35
...
58fb3782de
Author | SHA1 | Date | |
---|---|---|---|
|
58fb3782de | ||
|
7737bea1a6 | ||
|
1354cfe6c8 |
Binary file not shown.
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 152 KiB |
@ -23,7 +23,7 @@
|
||||
ADSBDemodDisplayDialog::ADSBDemodDisplayDialog(
|
||||
int removeTimeout, float airportRange, ADSBDemodSettings::AirportType airportMinimumSize,
|
||||
bool displayHeliports, bool siUnits, QString fontName, int fontSize, bool displayDemodStats,
|
||||
bool autoResizeTableColumns, QWidget* parent) :
|
||||
bool autoResizeTableColumns, const QString& apiKey, QWidget* parent) :
|
||||
QDialog(parent),
|
||||
m_fontName(fontName),
|
||||
m_fontSize(fontSize),
|
||||
@ -37,6 +37,7 @@ ADSBDemodDisplayDialog::ADSBDemodDisplayDialog(
|
||||
ui->units->setCurrentIndex((int)siUnits);
|
||||
ui->displayStats->setChecked(displayDemodStats);
|
||||
ui->autoResizeTableColumns->setChecked(autoResizeTableColumns);
|
||||
ui->apiKey->setText(apiKey);
|
||||
}
|
||||
|
||||
ADSBDemodDisplayDialog::~ADSBDemodDisplayDialog()
|
||||
@ -53,6 +54,7 @@ void ADSBDemodDisplayDialog::accept()
|
||||
m_siUnits = ui->units->currentIndex() == 0 ? false : true;
|
||||
m_displayDemodStats = ui->displayStats->isChecked();
|
||||
m_autoResizeTableColumns = ui->autoResizeTableColumns->isChecked();
|
||||
m_apiKey = ui->apiKey->text();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ class ADSBDemodDisplayDialog : public QDialog {
|
||||
public:
|
||||
explicit ADSBDemodDisplayDialog(int removeTimeout, float airportRange, ADSBDemodSettings::AirportType airportMinimumSize,
|
||||
bool displayHeliports, bool siUnits, QString fontName, int fontSize, bool displayDemodStats,
|
||||
bool autoResizeTableColumns, QWidget* parent = 0);
|
||||
bool autoResizeTableColumns, const QString& apiKey, QWidget* parent = 0);
|
||||
~ADSBDemodDisplayDialog();
|
||||
|
||||
int m_removeTimeout;
|
||||
@ -39,6 +39,7 @@ public:
|
||||
int m_fontSize;
|
||||
bool m_displayDemodStats;
|
||||
bool m_autoResizeTableColumns;
|
||||
QString m_apiKey;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>351</width>
|
||||
<height>289</height>
|
||||
<width>417</width>
|
||||
<height>287</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -23,17 +23,31 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="5" column="1">
|
||||
<widget class="QPushButton" name="font">
|
||||
<property name="toolTip">
|
||||
<string>Select a font for the table</string>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="airportSizeLabel">
|
||||
<property name="text">
|
||||
<string>Select...</string>
|
||||
<string>Display airports with size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="units">
|
||||
<property name="toolTip">
|
||||
<string>The units to use for altitude, speed and climb rate</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ft, kn, ft/min</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>m, kph, m/s</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="timeoutLabel">
|
||||
<property name="text">
|
||||
<string>Aircraft timeout (s)</string>
|
||||
@ -50,70 +64,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="heliports">
|
||||
<property name="toolTip">
|
||||
<string>When checked, heliports are displayed on the map</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Display heliports</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="timeout">
|
||||
<property name="toolTip">
|
||||
<string>How long in seconds after not receiving any frames will an aircraft be removed from the table and map</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="airportSizeLabel">
|
||||
<property name="text">
|
||||
<string>Display airports with size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="airportRangeLabel">
|
||||
<property name="text">
|
||||
<string>Airport display distance (km)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="fontLabel">
|
||||
<property name="text">
|
||||
<string>Table font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="displayStats">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display demodulator statistics</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Display demodulator statistics</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="unitsLabel">
|
||||
<property name="text">
|
||||
<string>Units</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="airportSize">
|
||||
<property name="toolTip">
|
||||
@ -136,31 +86,129 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="unitsLabel">
|
||||
<property name="text">
|
||||
<string>Units</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QPushButton" name="font">
|
||||
<property name="toolTip">
|
||||
<string>Select a font for the table</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="timeout">
|
||||
<property name="toolTip">
|
||||
<string>How long in seconds after not receiving any frames will an aircraft be removed from the table and map</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="airportRangeLabel">
|
||||
<property name="text">
|
||||
<string>Airport display distance (km)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="fontLabel">
|
||||
<property name="text">
|
||||
<string>Table font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="apiKeyLabel">
|
||||
<property name="text">
|
||||
<string>avaitionstack API key</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="autoResizeTableColumns">
|
||||
<property name="toolTip">
|
||||
<string>Resize the columns in the table after an aircraft is added to it</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="autoResizeTableColumnsLabel">
|
||||
<property name="text">
|
||||
<string>Resize columns after adding aircraft</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="units">
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="heliports">
|
||||
<property name="toolTip">
|
||||
<string>The units to use for altitude, speed and climb rate</string>
|
||||
<string>When checked, heliports are displayed on the map</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ft, kn, ft/min</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="displayStats">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Display demodulator statistics</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>m, kph, m/s</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="heliportsLabel">
|
||||
<property name="text">
|
||||
<string>Display heliports</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="displayStatsLabel">
|
||||
<property name="text">
|
||||
<string>Display demodulator statistics</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="apiKey">
|
||||
<property name="toolTip">
|
||||
<string>aviationstack.com API key for accessing flight information</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -160,9 +160,9 @@ QString Aircraft::getImage()
|
||||
QString Aircraft::getText(bool all)
|
||||
{
|
||||
QStringList list;
|
||||
if (m_flight.length() > 0)
|
||||
if (m_callsign.length() > 0)
|
||||
{
|
||||
list.append(QString("Flight: %1").arg(m_flight));
|
||||
list.append(QString("Callsign: %1").arg(m_callsign));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -215,10 +215,54 @@ QString Aircraft::getText(bool all)
|
||||
desc = QString("Descending: %1 (%2)").arg(rate).arg(units);
|
||||
list.append(QString(desc));
|
||||
}
|
||||
if ((m_status.length() > 0) && m_status.compare("No emergency"))
|
||||
{
|
||||
if ((m_status.length() > 0) && m_status.compare("No emergency")) {
|
||||
list.append(m_status);
|
||||
}
|
||||
|
||||
QString flightStatus = m_flightStatusItem->text();
|
||||
if (!flightStatus.isEmpty()) {
|
||||
list.append(QString("Flight status: %1").arg(flightStatus));
|
||||
}
|
||||
QString dep = m_depItem->text();
|
||||
if (!dep.isEmpty()) {
|
||||
list.append(QString("Departed: %1").arg(dep));
|
||||
}
|
||||
QString std = m_stdItem->text();
|
||||
if (!std.isEmpty()) {
|
||||
list.append(QString("STD: %1").arg(std));
|
||||
}
|
||||
QString atd = m_atdItem->text();
|
||||
if (!atd.isEmpty())
|
||||
{
|
||||
list.append(QString("ATD: %1").arg(atd));
|
||||
}
|
||||
else
|
||||
{
|
||||
QString etd = m_etdItem->text();
|
||||
if (!etd.isEmpty()) {
|
||||
list.append(QString("ETD: %1").arg(etd));
|
||||
}
|
||||
}
|
||||
QString arr = m_arrItem->text();
|
||||
if (!arr.isEmpty()) {
|
||||
list.append(QString("Arrival: %1").arg(arr));
|
||||
}
|
||||
QString sta = m_staItem->text();
|
||||
if (!sta.isEmpty()) {
|
||||
list.append(QString("STA: %1").arg(sta));
|
||||
}
|
||||
QString ata = m_ataItem->text();
|
||||
if (!ata.isEmpty())
|
||||
{
|
||||
list.append(QString("ATA: %1").arg(ata));
|
||||
}
|
||||
else
|
||||
{
|
||||
QString eta = m_etaItem->text();
|
||||
if (!eta.isEmpty()) {
|
||||
list.append(QString("ETA: %1").arg(eta));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list.join("\n");
|
||||
}
|
||||
@ -501,6 +545,8 @@ QIcon *ADSBDemodGUI::getAirlineIcon(const QString &operatorICAO)
|
||||
icon = new QIcon(":" + endPath);
|
||||
m_airlineIcons.insert(operatorICAO, icon);
|
||||
}
|
||||
else
|
||||
qDebug() << "ADSBDemodGUI: No airline logo for " << operatorICAO;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
@ -611,7 +657,7 @@ void ADSBDemodGUI::handleADSB(
|
||||
int row = ui->adsbData->rowCount();
|
||||
ui->adsbData->setRowCount(row + 1);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ICAO, aircraft->m_icaoItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_FLIGHT, aircraft->m_flightItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_CALLSIGN, aircraft->m_callsignItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_MODEL, aircraft->m_modelItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_AIRLINE, aircraft->m_airlineItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ALTITUDE, aircraft->m_altitudeItem);
|
||||
@ -635,6 +681,15 @@ void ADSBDemodGUI::handleADSB(
|
||||
ui->adsbData->setItem(row, ADSB_COL_FRAMECOUNT, aircraft->m_adsbFrameCountItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_CORRELATION, aircraft->m_correlationItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_RSSI, aircraft->m_rssiItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_FLIGHT_STATUS, aircraft->m_flightStatusItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_DEP, aircraft->m_depItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ARR, aircraft->m_arrItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_STD, aircraft->m_stdItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ETD, aircraft->m_etdItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ATD, aircraft->m_atdItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_STA, aircraft->m_staItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ETA, aircraft->m_etaItem);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ATA, aircraft->m_ataItem);
|
||||
// Look aircraft up in database
|
||||
if (m_aircraftInfo != nullptr)
|
||||
{
|
||||
@ -764,8 +819,39 @@ void ADSBDemodGUI::handleADSB(
|
||||
callsign[i] = idMap[c[i]];
|
||||
callsign[8] = '\0';
|
||||
|
||||
aircraft->m_flight = QString(callsign);
|
||||
aircraft->m_flightItem->setText(aircraft->m_flight);
|
||||
aircraft->m_callsign = QString(callsign).trimmed();
|
||||
aircraft->m_callsignItem->setText(aircraft->m_callsign);
|
||||
|
||||
// Attempt to map callsign to flight number
|
||||
if (!aircraft->m_callsign.isEmpty())
|
||||
{
|
||||
QRegularExpression flightNoExp("^[A-Z]{2,3}[0-9]{1,4}$");
|
||||
// Airlines line BA add a single charater suffix that can be stripped
|
||||
// If the suffix is two characters, then it typically means a digit
|
||||
// has been replaced which I don't know how to guess
|
||||
// E.g Easyjet might use callsign EZY67JQ for flight EZY6267
|
||||
// BA use BAW90BG for BA890
|
||||
QRegularExpression suffixedFlightNoExp("^([A-Z]{2,3})([0-9]{1,4})[A-Z]?$");
|
||||
QRegularExpressionMatch suffixMatch;
|
||||
|
||||
if (flightNoExp.match(aircraft->m_callsign).hasMatch())
|
||||
{
|
||||
aircraft->m_flight = aircraft->m_callsign;
|
||||
}
|
||||
else if ((suffixMatch = suffixedFlightNoExp.match(aircraft->m_callsign)).hasMatch())
|
||||
{
|
||||
aircraft->m_flight = QString("%1%2").arg(suffixMatch.captured(1)).arg(suffixMatch.captured(2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't guess, to save wasting API calls
|
||||
aircraft->m_flight = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aircraft->m_flight = "";
|
||||
}
|
||||
}
|
||||
else if (((tc >= 5) && (tc <= 18)) || ((tc >= 20) && (tc <= 22)))
|
||||
{
|
||||
@ -1136,11 +1222,11 @@ void ADSBDemodGUI::checkStaticNotification(Aircraft *aircraft)
|
||||
}
|
||||
if (!match.isEmpty())
|
||||
{
|
||||
//QRegularExpression regExp(m_settings.m_notificationSettings[i]->m_regExp);
|
||||
if (m_settings.m_notificationSettings[i]->m_regularExpression.isValid())
|
||||
{
|
||||
if (m_settings.m_notificationSettings[i]->m_regularExpression.match(match).hasMatch())
|
||||
{
|
||||
highlightAircraft(aircraft);
|
||||
if (!m_settings.m_notificationSettings[i]->m_speech.isEmpty()) {
|
||||
speechNotification(aircraft, m_settings.m_notificationSettings[i]->m_speech);
|
||||
}
|
||||
@ -1160,7 +1246,7 @@ void ADSBDemodGUI::checkDynamicNotification(Aircraft *aircraft)
|
||||
{
|
||||
for (int i = 0; i < m_settings.m_notificationSettings.size(); i++)
|
||||
{
|
||||
if ( (m_settings.m_notificationSettings[i]->m_matchColumn == ADSB_COL_FLIGHT)
|
||||
if ( (m_settings.m_notificationSettings[i]->m_matchColumn == ADSB_COL_CALLSIGN)
|
||||
|| (m_settings.m_notificationSettings[i]->m_matchColumn == ADSB_COL_ALTITUDE)
|
||||
|| (m_settings.m_notificationSettings[i]->m_matchColumn == ADSB_COL_SPEED)
|
||||
|| (m_settings.m_notificationSettings[i]->m_matchColumn == ADSB_COL_RANGE)
|
||||
@ -1172,8 +1258,8 @@ void ADSBDemodGUI::checkDynamicNotification(Aircraft *aircraft)
|
||||
QString match;
|
||||
switch (m_settings.m_notificationSettings[i]->m_matchColumn)
|
||||
{
|
||||
case ADSB_COL_FLIGHT:
|
||||
match = aircraft->m_flightItem->data(Qt::DisplayRole).toString();
|
||||
case ADSB_COL_CALLSIGN:
|
||||
match = aircraft->m_callsignItem->data(Qt::DisplayRole).toString();
|
||||
break;
|
||||
case ADSB_COL_ALTITUDE:
|
||||
match = aircraft->m_altitudeItem->data(Qt::DisplayRole).toString();
|
||||
@ -1202,6 +1288,7 @@ void ADSBDemodGUI::checkDynamicNotification(Aircraft *aircraft)
|
||||
{
|
||||
if (m_settings.m_notificationSettings[i]->m_regularExpression.match(match).hasMatch())
|
||||
{
|
||||
highlightAircraft(aircraft);
|
||||
if (!m_settings.m_notificationSettings[i]->m_speech.isEmpty()) {
|
||||
speechNotification(aircraft, m_settings.m_notificationSettings[i]->m_speech);
|
||||
}
|
||||
@ -1231,7 +1318,7 @@ QString ADSBDemodGUI::subAircraftString(Aircraft *aircraft, const QString &strin
|
||||
{
|
||||
QString s = string;
|
||||
s = s.replace("${icao}", aircraft->m_icaoItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${flight}", aircraft->m_flightItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${callsign}", aircraft->m_callsignItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${aircraft}", aircraft->m_modelItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${latitude}", aircraft->m_latitudeItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${longitude}", aircraft->m_longitudeItem->data(Qt::DisplayRole).toString());
|
||||
@ -1246,6 +1333,15 @@ QString ADSBDemodGUI::subAircraftString(Aircraft *aircraft, const QString &strin
|
||||
s = s.replace("${manufacturer}", aircraft->m_manufacturerNameItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${owner}", aircraft->m_ownerItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${operator}", aircraft->m_operatorICAOItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${flightstatus}", aircraft->m_flightStatusItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${departure}", aircraft->m_depItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${arrival}", aircraft->m_arrItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${std}", aircraft->m_stdItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${etd}", aircraft->m_etdItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${atd}", aircraft->m_atdItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${sta}", aircraft->m_staItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${eta}", aircraft->m_etaItem->data(Qt::DisplayRole).toString());
|
||||
s = s.replace("${ata}", aircraft->m_ataItem->data(Qt::DisplayRole).toString());
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -1364,6 +1460,45 @@ void ADSBDemodGUI::on_notifications_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void ADSBDemodGUI::on_flightInfo_clicked()
|
||||
{
|
||||
if (m_flightInformation)
|
||||
{
|
||||
// Selection mode is single, so only a single row should be returned
|
||||
QModelIndexList indexList = ui->adsbData->selectionModel()->selectedRows();
|
||||
if (!indexList.isEmpty())
|
||||
{
|
||||
int row = indexList.at(0).row();
|
||||
int icao = ui->adsbData->item(row, 0)->text().toInt(nullptr, 16);
|
||||
if (m_aircraft.contains(icao))
|
||||
{
|
||||
Aircraft *aircraft = m_aircraft.value(icao);
|
||||
if (!aircraft->m_flight.isEmpty())
|
||||
{
|
||||
// Download flight information
|
||||
m_flightInformation->getFlightInformation(aircraft->m_flight);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "ADSBDemodGUI::on_flightInfo_clicked - No flight number for selected aircraft";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "ADSBDemodGUI::on_flightInfo_clicked - No aircraft with icao " << icao;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "ADSBDemodGUI::on_flightInfo_clicked - No aircraft selected";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "ADSBDemodGUI::on_flightInfo_clicked - No flight information service - have you set an API key?";
|
||||
}
|
||||
}
|
||||
|
||||
void ADSBDemodGUI::on_adsbData_cellClicked(int row, int column)
|
||||
{
|
||||
(void) column;
|
||||
@ -1387,12 +1522,12 @@ void ADSBDemodGUI::on_adsbData_cellDoubleClicked(int row, int column)
|
||||
{
|
||||
Aircraft *aircraft = m_aircraft.value(icao);
|
||||
|
||||
if (column == ADSB_COL_FLIGHT)
|
||||
if (column == ADSB_COL_CALLSIGN)
|
||||
{
|
||||
if (aircraft->m_flight.length() > 0)
|
||||
if (!aircraft->m_callsign.isEmpty())
|
||||
{
|
||||
// Search for flight on flightradar24
|
||||
QDesktopServices::openUrl(QUrl(QString("https://www.flightradar24.com/%1").arg(aircraft->m_flight.trimmed())));
|
||||
QDesktopServices::openUrl(QUrl(QString("https://www.flightradar24.com/%1").arg(aircraft->m_callsign)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1876,7 +2011,8 @@ void ADSBDemodGUI::on_displaySettings_clicked()
|
||||
ADSBDemodDisplayDialog dialog(m_settings.m_removeTimeout, m_settings.m_airportRange, m_settings.m_airportMinimumSize,
|
||||
m_settings.m_displayHeliports, m_settings.m_siUnits,
|
||||
m_settings.m_tableFontName, m_settings.m_tableFontSize,
|
||||
m_settings.m_displayDemodStats, m_settings.m_autoResizeTableColumns);
|
||||
m_settings.m_displayDemodStats, m_settings.m_autoResizeTableColumns,
|
||||
m_settings.m_apiKey);
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
bool unitsChanged = m_settings.m_siUnits != dialog.m_siUnits;
|
||||
@ -1890,6 +2026,7 @@ void ADSBDemodGUI::on_displaySettings_clicked()
|
||||
m_settings.m_tableFontSize = dialog.m_fontSize;
|
||||
m_settings.m_displayDemodStats = dialog.m_displayDemodStats;
|
||||
m_settings.m_autoResizeTableColumns = dialog.m_autoResizeTableColumns;
|
||||
m_settings.m_apiKey = dialog.m_apiKey;
|
||||
|
||||
if (unitsChanged)
|
||||
m_aircraftModel.allAircraftUpdated();
|
||||
@ -2027,6 +2164,8 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
||||
// Initialise text to speech engine
|
||||
m_speech = new QTextToSpeech(this);
|
||||
|
||||
m_flightInformation = nullptr;
|
||||
|
||||
updateDeviceSetList();
|
||||
displaySettings();
|
||||
applySettings(true);
|
||||
@ -2042,6 +2181,11 @@ ADSBDemodGUI::~ADSBDemodGUI()
|
||||
delete a;
|
||||
++i;
|
||||
}
|
||||
if (m_flightInformation)
|
||||
{
|
||||
disconnect(m_flightInformation, &FlightInformation::flightUpdated, this, &ADSBDemodGUI::flightInformationUpdated);
|
||||
delete m_flightInformation;
|
||||
}
|
||||
}
|
||||
|
||||
void ADSBDemodGUI::applySettings(bool force)
|
||||
@ -2141,6 +2285,8 @@ void ADSBDemodGUI::displaySettings()
|
||||
if (!m_settings.m_displayDemodStats)
|
||||
ui->stats->setText("");
|
||||
|
||||
initFlightInformation();
|
||||
|
||||
blockApplySettings(false);
|
||||
}
|
||||
|
||||
@ -2242,7 +2388,7 @@ void ADSBDemodGUI::resizeTable()
|
||||
int row = ui->adsbData->rowCount();
|
||||
ui->adsbData->setRowCount(row + 1);
|
||||
ui->adsbData->setItem(row, ADSB_COL_ICAO, new QTableWidgetItem("ICAO ID"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_FLIGHT, new QTableWidgetItem("Flight No."));
|
||||
ui->adsbData->setItem(row, ADSB_COL_CALLSIGN, new QTableWidgetItem("Callsign"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_MODEL, new QTableWidgetItem("Aircraft12345"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_AIRLINE, new QTableWidgetItem("airbrigdecargo1"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_ALTITUDE, new QTableWidgetItem("Alt (ft)"));
|
||||
@ -2266,31 +2412,96 @@ void ADSBDemodGUI::resizeTable()
|
||||
ui->adsbData->setItem(row, ADSB_COL_FRAMECOUNT, new QTableWidgetItem("Frames"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_CORRELATION, new QTableWidgetItem("0.001/0.001/0.001"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_RSSI, new QTableWidgetItem("-100.0"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_FLIGHT_STATUS, new QTableWidgetItem("scheduled"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_DEP, new QTableWidgetItem("WWWW"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_ARR, new QTableWidgetItem("WWWW"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_STD, new QTableWidgetItem("12:00 -1"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_ETD, new QTableWidgetItem("12:00 -1"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_ATD, new QTableWidgetItem("12:00 -1"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_STA, new QTableWidgetItem("12:00 +1"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_ETA, new QTableWidgetItem("12:00 +1"));
|
||||
ui->adsbData->setItem(row, ADSB_COL_ATA, new QTableWidgetItem("12:00 +1"));
|
||||
ui->adsbData->resizeColumnsToContents();
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_ICAO);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_FLIGHT);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_MODEL);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_AIRLINE);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_ALTITUDE);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_SPEED);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_HEADING);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_VERTICALRATE);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_RANGE);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_AZEL);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_LATITUDE);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_LONGITUDE);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_CATEGORY);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_STATUS);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_SQUAWK);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_REGISTRATION);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_COUNTRY);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_REGISTERED);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_MANUFACTURER);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_OWNER);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_OPERATOR_ICAO);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_TIME);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_FRAMECOUNT);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_CORRELATION);
|
||||
ui->adsbData->removeCellWidget(row, ADSB_COL_RSSI);
|
||||
ui->adsbData->setRowCount(row);
|
||||
}
|
||||
|
||||
Aircraft* ADSBDemodGUI::findAircraftByFlight(const QString& flight)
|
||||
{
|
||||
QHash<int, Aircraft *>::iterator i = m_aircraft.begin();
|
||||
while (i != m_aircraft.end())
|
||||
{
|
||||
Aircraft *aircraft = i.value();
|
||||
if (aircraft->m_flight == flight) {
|
||||
return aircraft;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Convert to hh:mm (+/-days)
|
||||
QString ADSBDemodGUI::dataTimeToShortString(QDateTime dt)
|
||||
{
|
||||
if (dt.isValid())
|
||||
{
|
||||
QDate currentDate = QDateTime::currentDateTimeUtc().date();
|
||||
if (dt.date() == currentDate)
|
||||
{
|
||||
return dt.time().toString("hh:mm");
|
||||
}
|
||||
else
|
||||
{
|
||||
int days = currentDate.daysTo(dt.date());
|
||||
if (days >= 0) {
|
||||
return QString("%1 +%2").arg(dt.time().toString("hh:mm")).arg(days);
|
||||
} else {
|
||||
return QString("%1 %2").arg(dt.time().toString("hh:mm")).arg(days);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void ADSBDemodGUI::initFlightInformation()
|
||||
{
|
||||
if (m_flightInformation)
|
||||
{
|
||||
disconnect(m_flightInformation, &FlightInformation::flightUpdated, this, &ADSBDemodGUI::flightInformationUpdated);
|
||||
delete m_flightInformation;
|
||||
m_flightInformation = nullptr;
|
||||
}
|
||||
if (!m_settings.m_apiKey.isEmpty())
|
||||
{
|
||||
m_flightInformation = FlightInformation::create(m_settings.m_apiKey);
|
||||
if (m_flightInformation) {
|
||||
connect(m_flightInformation, &FlightInformation::flightUpdated, this, &ADSBDemodGUI::flightInformationUpdated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ADSBDemodGUI::flightInformationUpdated(const FlightInformation::Flight& flight)
|
||||
{
|
||||
Aircraft* aircraft = findAircraftByFlight(flight.m_flightICAO);
|
||||
if (aircraft)
|
||||
{
|
||||
aircraft->m_flightStatusItem->setText(flight.m_flightStatus);
|
||||
aircraft->m_depItem->setText(flight.m_departureICAO);
|
||||
aircraft->m_arrItem->setText(flight.m_arrivalICAO);
|
||||
aircraft->m_stdItem->setText(dataTimeToShortString(flight.m_departureScheduled));
|
||||
aircraft->m_etdItem->setText(dataTimeToShortString(flight.m_departureEstimated));
|
||||
aircraft->m_atdItem->setText(dataTimeToShortString(flight.m_departureActual));
|
||||
aircraft->m_staItem->setText(dataTimeToShortString(flight.m_arrivalScheduled));
|
||||
aircraft->m_etaItem->setText(dataTimeToShortString(flight.m_arrivalEstimated));
|
||||
aircraft->m_ataItem->setText(dataTimeToShortString(flight.m_arrivalActual));
|
||||
if (aircraft->m_positionValid) {
|
||||
m_aircraftModel.aircraftUpdated(aircraft);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "ADSBDemodGUI::flightInformationUpdated - Flight not found in ADS-B table: " << flight.m_flightICAO;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "util/azel.h"
|
||||
#include "util/movingaverage.h"
|
||||
#include "util/httpdownloadmanager.h"
|
||||
#include "util/flightinformation.h"
|
||||
#include "maincore.h"
|
||||
|
||||
#include "adsbdemodsettings.h"
|
||||
@ -78,7 +79,8 @@ public:
|
||||
// Data about an aircraft extracted from an ADS-B frames
|
||||
struct Aircraft {
|
||||
int m_icao; // 24-bit ICAO aircraft address
|
||||
QString m_flight; // Flight callsign
|
||||
QString m_callsign; // Flight callsign
|
||||
QString m_flight; // Guess at flight number
|
||||
Real m_latitude; // Latitude in decimal degrees
|
||||
Real m_longitude; // Longitude in decimal degrees
|
||||
int m_altitude; // Altitude in feet
|
||||
@ -130,7 +132,7 @@ struct Aircraft {
|
||||
|
||||
// GUI table items for above data
|
||||
QTableWidgetItem *m_icaoItem;
|
||||
QTableWidgetItem *m_flightItem;
|
||||
QTableWidgetItem *m_callsignItem;
|
||||
QTableWidgetItem *m_modelItem;
|
||||
QTableWidgetItem *m_airlineItem;
|
||||
QTableWidgetItem *m_latitudeItem;
|
||||
@ -154,6 +156,15 @@ struct Aircraft {
|
||||
QTableWidgetItem *m_adsbFrameCountItem;
|
||||
QTableWidgetItem *m_correlationItem;
|
||||
QTableWidgetItem *m_rssiItem;
|
||||
QTableWidgetItem *m_flightStatusItem;
|
||||
QTableWidgetItem *m_depItem;
|
||||
QTableWidgetItem *m_arrItem;
|
||||
QTableWidgetItem *m_stdItem;
|
||||
QTableWidgetItem *m_etdItem;
|
||||
QTableWidgetItem *m_atdItem;
|
||||
QTableWidgetItem *m_staItem;
|
||||
QTableWidgetItem *m_etaItem;
|
||||
QTableWidgetItem *m_ataItem;
|
||||
|
||||
Aircraft(ADSBDemodGUI *gui) :
|
||||
m_icao(0),
|
||||
@ -187,7 +198,7 @@ struct Aircraft {
|
||||
}
|
||||
// These are deleted by QTableWidget
|
||||
m_icaoItem = new QTableWidgetItem();
|
||||
m_flightItem = new QTableWidgetItem();
|
||||
m_callsignItem = new QTableWidgetItem();
|
||||
m_modelItem = new QTableWidgetItem();
|
||||
m_airlineItem = new QTableWidgetItem();
|
||||
m_altitudeItem = new QTableWidgetItem();
|
||||
@ -211,6 +222,15 @@ struct Aircraft {
|
||||
m_adsbFrameCountItem = new QTableWidgetItem();
|
||||
m_correlationItem = new QTableWidgetItem();
|
||||
m_rssiItem = new QTableWidgetItem();
|
||||
m_flightStatusItem = new QTableWidgetItem();
|
||||
m_depItem = new QTableWidgetItem();
|
||||
m_arrItem = new QTableWidgetItem();
|
||||
m_stdItem = new QTableWidgetItem();
|
||||
m_etdItem = new QTableWidgetItem();
|
||||
m_atdItem = new QTableWidgetItem();
|
||||
m_staItem = new QTableWidgetItem();
|
||||
m_etaItem = new QTableWidgetItem();
|
||||
m_ataItem = new QTableWidgetItem();
|
||||
}
|
||||
|
||||
QString getImage();
|
||||
@ -219,8 +239,8 @@ struct Aircraft {
|
||||
// Name to use when selected as a target
|
||||
QString targetName()
|
||||
{
|
||||
if (!m_flight.isEmpty())
|
||||
return QString("Flight: %1").arg(m_flight);
|
||||
if (!m_callsign.isEmpty())
|
||||
return QString("Callsign: %1").arg(m_callsign);
|
||||
else
|
||||
return QString("ICAO: %1").arg(m_icao, 0, 16);
|
||||
}
|
||||
@ -480,6 +500,7 @@ public:
|
||||
public slots:
|
||||
void channelMarkerChangedByCursor();
|
||||
void channelMarkerHighlightedByCursor();
|
||||
void flightInformationUpdated(const FlightInformation::Flight& flight);
|
||||
|
||||
private:
|
||||
Ui::ADSBDemodGUI* ui;
|
||||
@ -516,7 +537,7 @@ private:
|
||||
|
||||
QTextToSpeech *m_speech;
|
||||
QMenu *menu; // Column select context menu
|
||||
|
||||
FlightInformation *m_flightInformation;
|
||||
WebAPIAdapterInterface *m_webAPIAdapterInterface;
|
||||
HttpDownloadManager m_dlm;
|
||||
QProgressDialog *m_progressDialog;
|
||||
@ -558,6 +579,9 @@ private:
|
||||
QIcon *getFlagIcon(const QString &country);
|
||||
void updateDeviceSetList();
|
||||
QAction *createCheckableItem(QString& text, int idx, bool checked);
|
||||
Aircraft* findAircraftByFlight(const QString& flight);
|
||||
QString dataTimeToShortString(QDateTime dt);
|
||||
void initFlightInformation();
|
||||
|
||||
void leaveEvent(QEvent*);
|
||||
void enterEvent(QEvent*);
|
||||
@ -579,6 +603,7 @@ private slots:
|
||||
void on_demodModeS_clicked(bool checked);
|
||||
void on_feed_clicked(bool checked);
|
||||
void on_notifications_clicked();
|
||||
void on_flightInfo_clicked();
|
||||
void on_getOSNDB_clicked();
|
||||
void on_getAirportDB_clicked();
|
||||
void on_flightPaths_clicked(bool checked);
|
||||
|
@ -613,7 +613,24 @@
|
||||
<normaloff>:/mono.png</normaloff>:/mono.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="flightInfo">
|
||||
<property name="toolTip">
|
||||
<string>Download flight information for selected aircraft</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/info.png</normaloff>:/info.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -721,10 +738,10 @@
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Flight No.</string>
|
||||
<string>Callsign</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Commercial flight number. Links to www.flightradar24.com</string>
|
||||
<string>Callsign. Links to www.flightradar24.com</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
@ -908,6 +925,78 @@
|
||||
<string>RSSI</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Flight Status</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Status of flight</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Dep</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Departure airport</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Arr</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Arrival airport</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>STD</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Scheduled time of departure</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ETD</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Estimated time of departure</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ATD</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Actual time of departure</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>STA</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Scheduled time of arrival</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ETA</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Estimated time of arrival</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ATA</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Actual time of arrival</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
// Map main ADS-B table column numbers to combo box indicies
|
||||
std::vector<int> ADSBDemodNotificationDialog::m_columnMap = {
|
||||
ADSB_COL_ICAO, ADSB_COL_FLIGHT, ADSB_COL_MODEL,
|
||||
ADSB_COL_ICAO, ADSB_COL_CALLSIGN, ADSB_COL_MODEL,
|
||||
ADSB_COL_ALTITUDE, ADSB_COL_SPEED, ADSB_COL_RANGE,
|
||||
ADSB_COL_CATEGORY, ADSB_COL_STATUS, ADSB_COL_SQUAWK,
|
||||
ADSB_COL_REGISTRATION, ADSB_COL_MANUFACTURER, ADSB_COL_OWNER, ADSB_COL_OPERATOR_ICAO
|
||||
@ -111,7 +111,7 @@ void ADSBDemodNotificationDialog::addRow(ADSBDemodSettings::NotificationSettings
|
||||
matchWidget->setLayout(pLayout);
|
||||
|
||||
match->addItem("ICAO ID");
|
||||
match->addItem("Flight No.");
|
||||
match->addItem("Callsign");
|
||||
match->addItem("Aircraft");
|
||||
match->addItem("Alt (ft)");
|
||||
match->addItem("Spd (kn)");
|
||||
|
@ -66,6 +66,7 @@ void ADSBDemodSettings::resetToDefaults()
|
||||
m_autoResizeTableColumns = false;
|
||||
m_interpolatorPhaseSteps = 4; // Higher than these two values will struggle to run in real-time
|
||||
m_interpolatorTapsPerPhase = 3.5f; // without gaining much improvement in PER
|
||||
m_apiKey = "";
|
||||
for (int i = 0; i < ADSBDEMOD_COLUMNS; i++)
|
||||
{
|
||||
m_columnIndexes[i] = i;
|
||||
@ -115,6 +116,7 @@ QByteArray ADSBDemodSettings::serialize() const
|
||||
s.writeBool(33, m_allFlightPaths);
|
||||
|
||||
s.writeBlob(34, serializeNotificationSettings(m_notificationSettings));
|
||||
s.writeString(35, m_apiKey);
|
||||
|
||||
for (int i = 0; i < ADSBDEMOD_COLUMNS; i++)
|
||||
s.writeS32(100 + i, m_columnIndexes[i]);
|
||||
@ -199,6 +201,7 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data)
|
||||
|
||||
d.readBlob(34, &blob);
|
||||
deserializeNotificationSettings(blob, m_notificationSettings);
|
||||
d.readString(35, &m_apiKey, "");
|
||||
|
||||
for (int i = 0; i < ADSBDEMOD_COLUMNS; i++)
|
||||
d.readS32(100 + i, &m_columnIndexes[i], i);
|
||||
@ -259,7 +262,7 @@ void ADSBDemodSettings::NotificationSettings::updateRegularExpression()
|
||||
{
|
||||
m_regularExpression.setPattern(m_regExp);
|
||||
m_regularExpression.optimize();
|
||||
if (m_regularExpression.isValid()) {
|
||||
if (!m_regularExpression.isValid()) {
|
||||
qDebug() << "ADSBDemod: Regular expression is not valid: " << m_regExp;
|
||||
}
|
||||
}
|
||||
|
@ -29,11 +29,11 @@
|
||||
class Serializable;
|
||||
|
||||
// Number of columns in the table
|
||||
#define ADSBDEMOD_COLUMNS 25
|
||||
#define ADSBDEMOD_COLUMNS 34
|
||||
|
||||
// ADS-B table columns
|
||||
#define ADSB_COL_ICAO 0
|
||||
#define ADSB_COL_FLIGHT 1
|
||||
#define ADSB_COL_CALLSIGN 1
|
||||
#define ADSB_COL_MODEL 2
|
||||
#define ADSB_COL_AIRLINE 3
|
||||
#define ADSB_COL_ALTITUDE 4
|
||||
@ -57,6 +57,15 @@ class Serializable;
|
||||
#define ADSB_COL_FRAMECOUNT 22
|
||||
#define ADSB_COL_CORRELATION 23
|
||||
#define ADSB_COL_RSSI 24
|
||||
#define ADSB_COL_FLIGHT_STATUS 25
|
||||
#define ADSB_COL_DEP 26
|
||||
#define ADSB_COL_ARR 27
|
||||
#define ADSB_COL_STD 28
|
||||
#define ADSB_COL_ETD 29
|
||||
#define ADSB_COL_ATD 30
|
||||
#define ADSB_COL_STA 31
|
||||
#define ADSB_COL_ETA 32
|
||||
#define ADSB_COL_ATA 33
|
||||
|
||||
struct ADSBDemodSettings
|
||||
{
|
||||
@ -119,6 +128,7 @@ struct ADSBDemodSettings
|
||||
float m_interpolatorTapsPerPhase;
|
||||
|
||||
QList<NotificationSettings *> m_notificationSettings;
|
||||
QString m_apiKey; //!< aviationstack.com API key
|
||||
|
||||
ADSBDemodSettings();
|
||||
void resetToDefaults();
|
||||
|
@ -67,6 +67,8 @@ Clicking the Display Settings button will open the Display Settings dialog, whic
|
||||
* Whether demodulator statistics are displayed (primarily an option for developers).
|
||||
* Whether the columns in the table are automatically resized after an aircraft is added to it. If unchecked, columns can be resized manually and should be saved with presets.
|
||||
|
||||
You can also enter an [avaiationstack](https://aviationstack.com/product) API key, needed to download flight information (such as departure and arrival airports and times).
|
||||
|
||||
<h3>12: Display Flight Paths</h3>
|
||||
|
||||
Checking this button draws a line on the map showing aircraft's flight paths, as determined from received ADS-B frames.
|
||||
@ -125,10 +127,10 @@ Emergency status are:
|
||||
* Unlawful interference
|
||||
* Downed aircraft
|
||||
|
||||
In the Speech and Command strings, variables can be used to substitute in ADS-B data for the aircraft:
|
||||
In the Speech and Command strings, variables can be used to substitute in data from the ADS-B table for the aircraft:
|
||||
|
||||
* ${icao},
|
||||
* ${flight}
|
||||
* ${callsign}
|
||||
* ${aircraft}
|
||||
* ${latitude}
|
||||
* ${longitude}
|
||||
@ -143,6 +145,23 @@ In the Speech and Command strings, variables can be used to substitute in ADS-B
|
||||
* ${manufacturer}
|
||||
* ${owner}
|
||||
* ${operator}
|
||||
* ${flightstatus}
|
||||
* ${departure}
|
||||
* ${arrival}
|
||||
* ${std}
|
||||
* ${etd}
|
||||
* ${atd}
|
||||
* ${sta}
|
||||
* ${eta}
|
||||
* ${ata}
|
||||
|
||||
<h3>Download flight information for selected flight</h3>
|
||||
|
||||
When clicked, flight information (departure and arrival airport and times) is downloaded for the aircraft highlighted in the ADS-B data table using the aviationstack.com API.
|
||||
To be able to use this, a callsign for the highlighted aircraft must have been received. Also, the callsign must be mappable to a flight number, which is not always possible (this is typically
|
||||
the case for callsigns that end in two characters, as for these, some digits from the flight number will have been omitted).
|
||||
|
||||
To use this feature, an (aviationstack)[aviationstack.com] API Key must be entered in the Display Settings dialog (11). A free key giving 500 API calls per month is (available)[https://aviationstack.com/product].
|
||||
|
||||
<h3>14: Refresh list of devices</h3>
|
||||
|
||||
@ -154,12 +173,12 @@ Specify the SDRangel device set that will be have its centre frequency set when
|
||||
|
||||
<h3>ADS-B Data</h3>
|
||||
|
||||
The table displays the decoded ADS-B data for each aircraft along side data available for the aircraft from the Opensky Network database. The data is not all able to be transmitted in a single ADS-B frame, so the table displays an amalgamation of the latest received data of each type.
|
||||
The table displays the decoded ADS-B data for each aircraft along side data available for the aircraft from the Opensky Network database (DB) and aviationstack (API). The data is not all able to be transmitted in a single ADS-B frame, so the table displays an amalgamation of the latest received data of each type.
|
||||
|
||||
![ADS-B Demodulator Data](../../../doc/img/ADSBDemod_plugin_table.png)
|
||||
|
||||
* ICAO ID - 24-bit hexidecimal ICAO aircraft address. This is unique for each aircraft. (ADS-B)
|
||||
* Flight No. - Airline flight number or callsign. (ADS-B)
|
||||
* Callsign - Aircraft callsign (which is sometimes also the flight number). (ADS-B)
|
||||
* Aircraft - The aircraft model. (DB)
|
||||
* Airline - The logo of the operator of the aircraft (or owner if no operator known). (DB)
|
||||
* Altitude (Alt) - Altitude in feet or metres. (ADS-B)
|
||||
@ -182,6 +201,15 @@ The table displays the decoded ADS-B data for each aircraft along side data avai
|
||||
* RX Frames - A count of the number of ADS-B frames received from this aircraft.
|
||||
* Correlation - Displays the minimun, average and maximum of the preamable correlation in dB for each recevied frame. These values can be used to help select a threshold setting. This correlation value is the ratio between the presence and absence of the signal corresponding to the "ones" and the "zeros" of the sync word adjusted by the bits ratio. It can be interpreted as a SNR estimation.
|
||||
* RSSI - This Received Signal Strength Indicator is based on the signal power during correlation estimation. This is the power sum during the expected presence of the signal i.e. the "ones" of the sync word.
|
||||
* Flight status - scheduled, active, landed, cancelled, incident or diverted. (API)
|
||||
* Dep - Departure airport. (API)
|
||||
* Arr - Arrival airport. (API)
|
||||
* STD - Scheduled time of departure. (API)
|
||||
* ETD - Estimated time of departure. (API)
|
||||
* ATD - Actual time of departure. (API)
|
||||
* STA - Scheduled time of arrival. (API)
|
||||
* ETA - Estimated time of arrival. (API)
|
||||
* ATA - Actual time of arrival. (API)
|
||||
|
||||
If an ADS-B frame has not been received from an aircraft for 60 seconds, the aircraft is removed from the table and map. This timeout can be adjusted in the Display Settings dialog.
|
||||
|
||||
@ -190,7 +218,7 @@ If an ADS-B frame has not been received from an aircraft for 60 seconds, the air
|
||||
* To reorder the columns, left click and drag left or right a column header.
|
||||
* Left click on a header to sort the table by the data in that column.
|
||||
* Double clicking in an ICAO ID cell will open a Web browser and search for the corresponding aircraft on https://www.planespotters.net/
|
||||
* Double clicking in an Flight No cell will open a Web browser and search for the corresponding flight on https://www.flightradar24.com/
|
||||
* Double clicking in an Callsign cell will open a Web browser and search for the corresponding flight on https://www.flightradar24.com/
|
||||
* Double clicking in an Az/El cell will set the aircraft as the active target. The azimuth and elevation to the aicraft will be sent to a rotator controller plugin. The aircraft information box will be coloured green, rather than blue, on the map.
|
||||
* Double clicking on any other cell in the table will centre the map on the corresponding aircraft.
|
||||
|
||||
|
@ -190,6 +190,7 @@ set(sdrbase_SOURCES
|
||||
util/db.cpp
|
||||
util/fixedtraits.cpp
|
||||
util/fits.cpp
|
||||
util/flightinformation.cpp
|
||||
util/golay2312.cpp
|
||||
util/httpdownloadmanager.cpp
|
||||
util/interpolation.cpp
|
||||
@ -397,6 +398,7 @@ set(sdrbase_HEADERS
|
||||
util/doublebuffermultiple.h
|
||||
util/fixedtraits.h
|
||||
util/fits.h
|
||||
util/flightinformation.h
|
||||
util/golay2312.h
|
||||
util/httpdownloadmanager.h
|
||||
util/incrementalarray.h
|
||||
|
164
sdrbase/util/flightinformation.cpp
Normal file
164
sdrbase/util/flightinformation.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "flightinformation.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
FlightInformation::FlightInformation()
|
||||
{
|
||||
}
|
||||
|
||||
FlightInformation* FlightInformation::create(const QString& apiKey, const QString& service)
|
||||
{
|
||||
if (service == "aviationstack.com")
|
||||
{
|
||||
if (!apiKey.isEmpty())
|
||||
{
|
||||
return new AviationStack(apiKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "FlightInformation::create: An API key is required for: " << service;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "FlightInformation::create: Unsupported service: " << service;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AviationStack::AviationStack(const QString& apiKey) :
|
||||
m_apiKey(apiKey)
|
||||
{
|
||||
m_networkManager = new QNetworkAccessManager();
|
||||
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleReply(QNetworkReply*)));
|
||||
}
|
||||
|
||||
AviationStack::~AviationStack()
|
||||
{
|
||||
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleReply(QNetworkReply*)));
|
||||
delete m_networkManager;
|
||||
}
|
||||
|
||||
void AviationStack::getFlightInformation(const QString& flight)
|
||||
{
|
||||
QUrl url(QString("http://api.aviationstack.com/v1/flights"));
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("flight_icao",flight);
|
||||
query.addQueryItem("access_key", m_apiKey);
|
||||
url.setQuery(query);
|
||||
|
||||
m_networkManager->get(QNetworkRequest(url));
|
||||
/*QFile file("flight.json");
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
parseJson(file.readAll());
|
||||
}*/
|
||||
}
|
||||
|
||||
void AviationStack::handleReply(QNetworkReply* reply)
|
||||
{
|
||||
if (reply)
|
||||
{
|
||||
if (!reply->error())
|
||||
{
|
||||
parseJson(reply->readAll());
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "AviationStack::handleReply: error: " << reply->error();
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "AviationStack::handleReply: reply is null";
|
||||
}
|
||||
}
|
||||
|
||||
void AviationStack::parseJson(QByteArray bytes)
|
||||
{
|
||||
QJsonDocument document = QJsonDocument::fromJson(bytes);
|
||||
if (document.isObject())
|
||||
{
|
||||
QJsonObject obj = document.object();
|
||||
if (obj.contains(QStringLiteral("data")))
|
||||
{
|
||||
QJsonArray data = obj.value(QStringLiteral("data")).toArray();
|
||||
if (data.size() > 0)
|
||||
{
|
||||
QJsonObject flightObj = data[0].toObject();
|
||||
|
||||
Flight flight;
|
||||
|
||||
if (flightObj.contains(QStringLiteral("flight_status"))) {
|
||||
flight.m_flightStatus = flightObj.value(QStringLiteral("flight_status")).toString();
|
||||
}
|
||||
if (flightObj.contains(QStringLiteral("departure")))
|
||||
{
|
||||
QJsonObject departure = flightObj.value(QStringLiteral("departure")).toObject();
|
||||
flight.m_departureAirport = departure.value(QStringLiteral("airport")).toString();
|
||||
flight.m_departureICAO = departure.value(QStringLiteral("icao")).toString();
|
||||
flight.m_departureTerminal = departure.value(QStringLiteral("terminal")).toString();
|
||||
flight.m_departureGate = departure.value(QStringLiteral("gate")).toString();
|
||||
flight.m_departureScheduled = QDateTime::fromString(departure.value(QStringLiteral("scheduled")).toString(), Qt::ISODate);
|
||||
flight.m_departureEstimated = QDateTime::fromString(departure.value(QStringLiteral("estimated")).toString(), Qt::ISODate);
|
||||
flight.m_departureActual = QDateTime::fromString(departure.value(QStringLiteral("actual")).toString(), Qt::ISODate);
|
||||
}
|
||||
if (flightObj.contains(QStringLiteral("arrival")))
|
||||
{
|
||||
QJsonObject departure = flightObj.value(QStringLiteral("arrival")).toObject();
|
||||
flight.m_arrivalAirport = departure.value(QStringLiteral("airport")).toString();
|
||||
flight.m_arrivalICAO = departure.value(QStringLiteral("icao")).toString();
|
||||
flight.m_arrivalTerminal = departure.value(QStringLiteral("terminal")).toString();
|
||||
flight.m_arrivalGate = departure.value(QStringLiteral("gate")).toString();
|
||||
flight.m_arrivalScheduled = QDateTime::fromString(departure.value(QStringLiteral("scheduled")).toString(), Qt::ISODate);
|
||||
flight.m_arrivalEstimated = QDateTime::fromString(departure.value(QStringLiteral("estimated")).toString(), Qt::ISODate);
|
||||
flight.m_arrivalActual = QDateTime::fromString(departure.value(QStringLiteral("actual")).toString(), Qt::ISODate);
|
||||
}
|
||||
if (flightObj.contains(QStringLiteral("flight")))
|
||||
{
|
||||
QJsonObject flightNo = flightObj.value(QStringLiteral("flight")).toObject();
|
||||
flight.m_flightICAO = flightNo.value(QStringLiteral("icao")).toString();
|
||||
flight.m_flightIATA = flightNo.value(QStringLiteral("iata")).toString();
|
||||
}
|
||||
emit flightUpdated(flight);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "AviationStack::handleReply: data array is empty";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "AviationStack::handleReply: Object doesn't contain data: " << obj;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "AviationStack::handleReply: Document is not an object: " << document;
|
||||
}
|
||||
}
|
90
sdrbase/util/flightinformation.h
Normal file
90
sdrbase/util/flightinformation.h
Normal file
@ -0,0 +1,90 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2021 Jon Beniston, M7RCE //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_FLIGHTINFORMATION_H
|
||||
#define INCLUDE_FLIGHTINFORMATION_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
// Flight information API wrapper
|
||||
// Allows searching for departure/arrival airports and status of a flight
|
||||
// Currently supports aviationstack.com
|
||||
class SDRBASE_API FlightInformation : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
FlightInformation();
|
||||
|
||||
public:
|
||||
struct Flight {
|
||||
QString m_flightICAO;
|
||||
QString m_flightIATA;
|
||||
QString m_flightStatus; // active, landed...
|
||||
QString m_departureAirport;
|
||||
QString m_departureICAO;
|
||||
QString m_departureTerminal;
|
||||
QString m_departureGate;
|
||||
QDateTime m_departureScheduled;
|
||||
QDateTime m_departureEstimated;
|
||||
QDateTime m_departureActual;
|
||||
QString m_arrivalAirport;
|
||||
QString m_arrivalICAO;
|
||||
QString m_arrivalTerminal;
|
||||
QString m_arrivalGate;
|
||||
QDateTime m_arrivalScheduled;
|
||||
QDateTime m_arrivalEstimated;
|
||||
QDateTime m_arrivalActual;
|
||||
};
|
||||
|
||||
static FlightInformation* create(const QString& apiKey, const QString& service="aviationstack.com");
|
||||
|
||||
virtual void getFlightInformation(const QString& flight) = 0;
|
||||
|
||||
signals:
|
||||
void flightUpdated(const Flight& flight); // Called when new data available.
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class SDRBASE_API AviationStack : public FlightInformation {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
AviationStack(const QString& apiKey);
|
||||
~AviationStack();
|
||||
virtual void getFlightInformation(const QString& flight) override;
|
||||
|
||||
private:
|
||||
void parseJson(QByteArray bytes);
|
||||
|
||||
QString m_apiKey;
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
|
||||
public slots:
|
||||
void handleReply(QNetworkReply* reply);
|
||||
|
||||
};
|
||||
|
||||
#endif /* INCLUDE_FLIGHTINFORMATION_H */
|
@ -39,13 +39,13 @@ Weather* Weather::create(const QString& apiKey, const QString& service)
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Weather::connect: An API key is required for: " << service;
|
||||
qDebug() << "Weather::create: An API key is required for: " << service;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Weather::connect: Unsupported service: " << service;
|
||||
qDebug() << "Weather::create: Unsupported service: " << service;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user