VOR Localizer: Use shared OpenAIP code to get latest URL

pull/1232/head
Jon Beniston 2022-05-03 13:44:09 +01:00
rodzic dba9a74acb
commit 14701da1f5
5 zmienionych plików z 127 dodań i 898 usunięć

Wyświetl plik

@ -34,7 +34,6 @@ if(NOT SERVER_MODE)
set(vor_HEADERS
${vor_HEADERS}
vorlocalizergui.h
navaid.h
)
set(TARGET_NAME vorlocalizer)

Wyświetl plik

@ -1,368 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_NAVAID_H
#define INCLUDE_NAVAID_H
#include <QString>
#include <QFile>
#include <QByteArray>
#include <QHash>
#include <QList>
#include <QDebug>
#include <QXmlStreamReader>
#include <stdio.h>
#include <string.h>
#include "util/units.h"
#include "util/csv.h"
#define OURAIRPORTS_NAVAIDS_URL "https://ourairports.com/data/navaids.csv"
#define OPENAIP_NAVAIDS_URL "https://www.openaip.net/customer_export_akfshb9237tgwiuvb4tgiwbf/%1_nav.aip"
struct NavAid {
int m_id;
QString m_ident; // 2 or 3 character ident
QString m_type; // VOR, VOR-DME or VORTAC
QString m_name;
float m_latitude;
float m_longitude;
float m_elevation;
int m_frequencykHz;
QString m_channel;
int m_range; // Nautical miles
float m_magneticDeclination;
bool m_alignedTrueNorth; // Is the VOR aligned to true North, rather than magnetic (may be the case at high latitudes)
static QString trimQuotes(const QString s)
{
if (s.startsWith('\"') && s.endsWith('\"'))
return s.mid(1, s.size() - 2);
else
return s;
}
int getRangeMetres()
{
return Units::nauticalMilesToIntegerMetres((float)m_range);
}
// OpenAIP XML file
static void readNavAidsXML(QHash<int, NavAid *> *navAidInfo, const QString &filename)
{
QFile file(filename);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QXmlStreamReader xmlReader(&file);
while(!xmlReader.atEnd() && !xmlReader.hasError())
{
if (xmlReader.readNextStartElement())
{
if (xmlReader.name() == "NAVAID")
{
QStringRef typeRef = xmlReader.attributes().value("TYPE");
if ((typeRef == QLatin1String("VOR"))
|| (typeRef== QLatin1String("VOR-DME"))
|| (typeRef == QLatin1String("VORTAC")))
{
QString type = typeRef.toString();
int identifier = 0;
QString name;
QString id;
float lat = 0.0f;
float lon = 0.0f;
float elevation = 0.0f;
int frequency = 0;
QString channel;
int range = 25;
float declination = 0.0f;
bool alignedTrueNorth = false;
while(xmlReader.readNextStartElement())
{
if (xmlReader.name() == QLatin1String("IDENTIFIER"))
identifier = xmlReader.readElementText().toInt();
else if (xmlReader.name() == QLatin1String("NAME"))
name = xmlReader.readElementText();
else if (xmlReader.name() == QLatin1String("ID"))
id = xmlReader.readElementText();
else if (xmlReader.name() == QLatin1String("GEOLOCATION"))
{
while(xmlReader.readNextStartElement())
{
if (xmlReader.name() == QLatin1String("LAT"))
lat = xmlReader.readElementText().toFloat();
else if (xmlReader.name() == QLatin1String("LON"))
lon = xmlReader.readElementText().toFloat();
else if (xmlReader.name() == QLatin1String("ELEV"))
elevation = xmlReader.readElementText().toFloat();
else
xmlReader.skipCurrentElement();
}
}
else if (xmlReader.name() == QLatin1String("RADIO"))
{
while(xmlReader.readNextStartElement())
{
if (xmlReader.name() == QLatin1String("FREQUENCY"))
frequency = (int)(xmlReader.readElementText().toFloat() * 1000);
else if (xmlReader.name() == QLatin1String("CHANNEL"))
channel = xmlReader.readElementText();
else
xmlReader.skipCurrentElement();
}
}
else if (xmlReader.name() == QLatin1String("PARAMS"))
{
while(xmlReader.readNextStartElement())
{
if (xmlReader.name() == QLatin1String("RANGE"))
range = xmlReader.readElementText().toInt();
else if (xmlReader.name() == QLatin1String("DECLINATION"))
declination = xmlReader.readElementText().toFloat();
else if (xmlReader.name() == QLatin1String("ALIGNEDTOTRUENORTH"))
alignedTrueNorth = xmlReader.readElementText() == "TRUE";
else
xmlReader.skipCurrentElement();
}
}
else
xmlReader.skipCurrentElement();
}
NavAid *vor = new NavAid();
vor->m_id = identifier;
vor->m_ident = id;
// Check idents conform to our filtering rules
if (vor->m_ident.size() < 2)
qDebug() << "Warning: VOR Ident less than 2 characters: " << vor->m_ident;
else if (vor->m_ident.size() > 3)
qDebug() << "Warning: VOR Ident greater than 3 characters: " << vor->m_ident;
vor->m_type = type;
vor->m_name = name;
vor->m_frequencykHz = frequency;
vor->m_channel = channel;
vor->m_latitude = lat;
vor->m_longitude = lon;
vor->m_elevation = elevation;
vor->m_range = range;
vor->m_magneticDeclination = declination;
vor->m_alignedTrueNorth = alignedTrueNorth;
navAidInfo->insert(identifier, vor);
}
}
}
}
file.close();
}
else
qDebug() << "NavAid::readNavAidsXML: Could not open " << filename << " for reading.";
}
// Read OurAirport's NavAids CSV file
// See comments for readOSNDB
static QHash<int, NavAid *> *readNavAidsDB(const QString &filename)
{
int cnt = 0;
QHash<int, NavAid *> *navAidInfo = nullptr;
// Column numbers used for the data as of 2020/10/28
int idCol = 0;
int identCol = 2;
int typeCol = 4;
int nameCol = 3;
int frequencyCol = 5;
int latitudeCol = 6;
int longitudeCol = 7;
int elevationCol = 8;
int powerCol = 18;
qDebug() << "NavAid::readNavAidsDB: " << filename;
FILE *file;
QByteArray utfFilename = filename.toUtf8();
QLocale cLocale(QLocale::C);
if ((file = fopen(utfFilename.constData(), "r")) != NULL)
{
char row[2048];
if (fgets(row, sizeof(row), file))
{
navAidInfo = new QHash<int, NavAid *>();
navAidInfo->reserve(15000);
// Read header
int idx = 0;
char *p = strtok(row, ",");
while (p != NULL)
{
if (!strcmp(p, "id"))
idCol = idx;
else if (!strcmp(p, "ident"))
identCol = idx;
else if (!strcmp(p, "type"))
typeCol = idx;
else if (!strcmp(p, "name"))
nameCol = idx;
else if (!strcmp(p, "frequency_khz"))
frequencyCol = idx;
else if (!strcmp(p, "latitude_deg"))
latitudeCol = idx;
else if (!strcmp(p, "longitude_deg"))
longitudeCol = idx;
else if (!strcmp(p, "elevation_ft"))
elevationCol = idx;
else if (!strcmp(p, "power"))
powerCol = idx;
p = strtok(NULL, ",");
idx++;
}
// Read data
while (fgets(row, sizeof(row), file))
{
int id = 0;
char *idString = NULL;
char *ident = NULL;
size_t identLen = 0;
char *type = NULL;
size_t typeLen = 0;
char *name = NULL;
size_t nameLen = 0;
char *frequencyString = NULL;
int frequency;
float latitude = 0.0f;
char *latitudeString = NULL;
size_t latitudeLen = 0;
float longitude = 0.0f;
char *longitudeString = NULL;
size_t longitudeLen = 0;
float elevation = 0.0f;
char *elevationString = NULL;
size_t elevationLen = 0;
char *power = NULL;
size_t powerLen = 0;
char *q = row;
idx = 0;
while ((p = csvNext(&q)) != nullptr)
{
// Read strings, stripping quotes
if (idx == idCol)
{
idString = p;
idString[strlen(idString)] = '\0';
id = strtol(idString, NULL, 10);
}
else if ((idx == identCol) && (p[0] == '\"'))
{
ident = p+1;
identLen = strlen(ident)-1;
ident[identLen] = '\0';
}
else if ((idx == typeCol) && (p[0] == '\"'))
{
type = p+1;
typeLen = strlen(type)-1;
type[typeLen] = '\0';
}
else if ((idx == nameCol) && (p[0] == '\"'))
{
name = p+1;
nameLen = strlen(name)-1;
name[nameLen] = '\0';
}
if (idx == frequencyCol)
{
frequencyString = p;
frequencyString[strlen(frequencyString)] = '\0';
frequency = strtol(frequencyString, NULL, 10);
}
else if (idx == latitudeCol)
{
latitudeString = p;
latitudeLen = strlen(latitudeString)-1;
latitudeString[latitudeLen] = '\0';
latitude = cLocale.toFloat(latitudeString);
}
else if (idx == longitudeCol)
{
longitudeString = p;
longitudeLen = strlen(longitudeString)-1;
longitudeString[longitudeLen] = '\0';
longitude = cLocale.toFloat(longitudeString);
}
else if (idx == elevationCol)
{
elevationString = p;
elevationLen = strlen(elevationString)-1;
elevationString[elevationLen] = '\0';
elevation = cLocale.toFloat(elevationString);
}
else if ((idx == powerCol) && (p[0] == '\"'))
{
power = p+1;
powerLen = strlen(power)-1;
power[powerLen] = '\0';
}
idx++;
}
// For now, we only want VORs
if (type && !strncmp(type, "VOR", 3))
{
NavAid *vor = new NavAid();
vor->m_id = id;
vor->m_ident = QString(ident);
// Check idents conform to our filtering rules
if (vor->m_ident.size() < 2)
qDebug() << "Warning: VOR Ident less than 2 characters: " << vor->m_ident;
else if (vor->m_ident.size() > 3)
qDebug() << "Warning: VOR Ident greater than 3 characters: " << vor->m_ident;
vor->m_type = QString(type);
vor->m_name = QString(name);
vor->m_frequencykHz = frequency;
vor->m_latitude = latitude;
vor->m_longitude = longitude;
vor->m_elevation = elevation;
if (power && !strcmp(power, "HIGH"))
vor->m_range = 100;
else if (power && !strcmp(power, "MEDIUM"))
vor->m_range = 40;
else
vor->m_range = 25;
vor->m_magneticDeclination = 0.0f;
vor->m_alignedTrueNorth = false;
navAidInfo->insert(id, vor);
cnt++;
}
}
}
fclose(file);
}
else
qDebug() << "NavAid::readNavAidsDB: Failed to open " << filename;
qDebug() << "NavAid::readNavAidsDB: Read " << cnt << " VORs";
return navAidInfo;
}
};
#endif // INCLUDE_NAVAID_H

Wyświetl plik

@ -47,258 +47,6 @@
#include "vorlocalizersettings.h"
#include "vorlocalizergui.h"
static const char *countryCodes[] = {
"ad",
"ae",
"af",
"ag",
"ai",
"al",
"am",
"an",
"ao",
"aq",
"ar",
"as",
"at",
"au",
"aw",
"ax",
"az",
"ba",
"bb",
"bd",
"be",
"bf",
"bg",
"bh",
"bi",
"bj",
"bl",
"bm",
"bn",
"bo",
"bq",
"br",
"bs",
"bt",
"bv",
"bw",
"by",
"bz",
"ca",
"cc",
"cd",
"cf",
"cg",
"ch",
"ci",
"ck",
"cl",
"cm",
"cn",
"co",
"cr",
"cu",
"cv",
"cw",
"cx",
"cy",
"cz",
"de",
"dj",
"dk",
"dm",
"do",
"dz",
"ec",
"ee",
"eg",
"eh",
"er",
"es",
"et",
"fi",
"fj",
"fk",
"fm",
"fo",
"fr",
"ga",
"gb",
"ge",
"gf",
"gg",
"gh",
"gi",
"gl",
"gm",
"gn",
"gp",
"gq",
"gr",
"gs",
"gt",
"gu",
"gw",
"gy",
"hk",
"hm",
"hn",
"hr",
"hu",
"id",
"ie",
"il",
"im",
"in",
"io",
"iq",
"ir",
"is",
"it",
"je",
"jm",
"jo",
"jp",
"ke",
"kg",
"kh",
"ki",
"km",
"kn",
"kp",
"kr",
"kw",
"ky",
"kz",
"la",
"lb",
"lc",
"li",
"lk",
"lr",
"ls",
"lt",
"lu",
"lv",
"ly",
"ma",
"mc",
"md",
"me",
"mf",
"mg",
"mh",
"mk",
"ml",
"mm",
"mn",
"mo",
"mp",
"mq",
"mr",
"ms",
"mt",
"mu",
"mv",
"mw",
"mx",
"my",
"mz",
"na",
"nc",
"ne",
"nf",
"ng",
"ni",
"nl",
"no",
"np",
"nr",
"nu",
"nz",
"om",
"pa",
"pe",
"pf",
"pg",
"ph",
"pk",
"pl",
"pm",
"pn",
"pr",
"ps",
"pt",
"pw",
"py",
"qa",
"re",
"ro",
"rs",
"ru",
"rw",
"sa",
"sb",
"sc",
"sd",
"se",
"sg",
"sh",
"si",
"sj",
"sk",
"sl",
"sm",
"sn",
"so",
"sr",
"ss",
"st",
"sv",
"sx",
"sy",
"sz",
"tc",
"td",
"tf",
"tg",
"th",
"tj",
"tk",
"tl",
"tm",
"tn",
"to",
"tr",
"tt",
"tv",
"tw",
"tz",
"ua",
"ug",
"um",
"us",
"uy",
"uz",
"va",
"vc",
"ve",
"vg",
"vi",
"vn",
"vu",
"wf",
"ws",
"ye",
"yt",
"za",
"zm",
"zw",
nullptr
};
// Lats and longs in decimal degrees. Distance in metres. Bearing in degrees.
// https://www.movable-type.co.uk/scripts/latlong.html
static void calcRadialEndPoint(float startLatitude, float startLongitude, float distance, float bearing, float &endLatitude, float &endLongitude)
@ -702,7 +450,7 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
// Add to settings to create corresponding demodulator
m_settings.m_subChannelSettings.insert(navId, VORLocalizerSubChannelSettings{
navId,
vorGUI->m_navAid->m_frequencykHz * 1000,
(int)(vorGUI->m_navAid->m_frequencykHz * 1000),
false
});
@ -725,23 +473,21 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
void VORLocalizerGUI::updateVORs()
{
m_vorModel.removeAllVORs();
QHash<int, NavAid *>::iterator i = m_vors->begin();
AzEl azEl = m_azEl;
while (i != m_vors->end())
for (auto vor : m_vors)
{
NavAid *vor = i.value();
if (vor->m_type.contains("VOR")) // Exclude DMEs
{
// Calculate distance to VOR from My Position
azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation));
azEl.calculate();
// Calculate distance to VOR from My Position
azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation));
azEl.calculate();
// Only display VOR if in range
if (azEl.getDistance() <= 200000) {
m_vorModel.addVOR(vor);
// Only display VOR if in range
if (azEl.getDistance() <= 200000) {
m_vorModel.addVOR(vor);
}
}
++i;
}
}
@ -807,41 +553,47 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
int subChannelId = report.getSubChannelId();
VORGUI *vorGUI = m_selectedVORs.value(subChannelId);
if (vorGUI)
{
// Display radial and signal magnitudes in table
// Display radial and signal magnitudes in table
Real varMagDB = std::round(20.0*std::log10(report.getVarMag()));
Real refMagDB = std::round(20.0*std::log10(report.getRefMag()));
Real varMagDB = std::round(20.0*std::log10(report.getVarMag()));
Real refMagDB = std::round(20.0*std::log10(report.getRefMag()));
bool validRadial = report.getValidRadial();
vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial()));
vorGUI->m_navIdItem->setData(Qt::DisplayRole, subChannelId);
bool validRadial = report.getValidRadial();
vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial()));
vorGUI->m_navIdItem->setData(Qt::DisplayRole, subChannelId);
if (validRadial) {
vorGUI->m_radialItem->setForeground(QBrush(Qt::white));
} else {
vorGUI->m_radialItem->setForeground(QBrush(Qt::red));
}
if (validRadial) {
vorGUI->m_radialItem->setForeground(QBrush(Qt::white));
} else {
vorGUI->m_radialItem->setForeground(QBrush(Qt::red));
vorGUI->m_refMagItem->setData(Qt::DisplayRole, refMagDB);
if (report.getValidRefMag()) {
vorGUI->m_refMagItem->setForeground(QBrush(Qt::white));
} else {
vorGUI->m_refMagItem->setForeground(QBrush(Qt::red));
}
vorGUI->m_varMagItem->setData(Qt::DisplayRole, varMagDB);
if (report.getValidVarMag()) {
vorGUI->m_varMagItem->setForeground(QBrush(Qt::white));
} else {
vorGUI->m_varMagItem->setForeground(QBrush(Qt::red));
}
// Update radial on map
m_vorModel.setRadial(subChannelId, validRadial, report.getRadial());
}
vorGUI->m_refMagItem->setData(Qt::DisplayRole, refMagDB);
if (report.getValidRefMag()) {
vorGUI->m_refMagItem->setForeground(QBrush(Qt::white));
} else {
vorGUI->m_refMagItem->setForeground(QBrush(Qt::red));
else
{
qDebug() << "VORLocalizerGUI::handleMessage: Got MsgReportRadial for non-existant subChannelId " << subChannelId;
}
vorGUI->m_varMagItem->setData(Qt::DisplayRole, varMagDB);
if (report.getValidVarMag()) {
vorGUI->m_varMagItem->setForeground(QBrush(Qt::white));
} else {
vorGUI->m_varMagItem->setForeground(QBrush(Qt::red));
}
// Update radial on map
m_vorModel.setRadial(subChannelId, validRadial, report.getRadial());
return true;
}
else if (VORLocalizerReport::MsgReportIdent::match(message))
@ -850,38 +602,45 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
int subChannelId = report.getSubChannelId();
VORGUI *vorGUI = m_selectedVORs.value(subChannelId);
QString ident = report.getIdent();
// Convert Morse to a string
QString identString = Morse::toString(ident);
// Idents should only be two or three characters, so filter anything else
// other than TEST which indicates a VOR is under maintainance (may also be TST)
if (((identString.size() >= 2) && (identString.size() <= 3)) || (identString == "TEST"))
if (vorGUI)
{
vorGUI->m_rxIdentItem->setText(identString);
vorGUI->m_rxMorseItem->setText(Morse::toSpacedUnicode(ident));
if (vorGUI->m_navAid->m_ident == identString)
QString ident = report.getIdent();
// Convert Morse to a string
QString identString = Morse::toString(ident);
// Idents should only be two or three characters, so filter anything else
// other than TEST which indicates a VOR is under maintainance (may also be TST)
if (((identString.size() >= 2) && (identString.size() <= 3)) || (identString == "TEST"))
{
// Set colour to green if matching expected ident
vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::green));
vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::green));
vorGUI->m_rxIdentItem->setText(identString);
vorGUI->m_rxMorseItem->setText(Morse::toSpacedUnicode(ident));
if (vorGUI->m_navAid->m_ident == identString)
{
// Set colour to green if matching expected ident
vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::green));
vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::green));
}
else
{
// Set colour to green if not matching expected ident
vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::red));
vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::red));
}
}
else
{
// Set colour to green if not matching expected ident
vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::red));
vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::red));
// Set yellow to indicate we've filtered something (unless red)
if (vorGUI->m_rxIdentItem->foreground().color() != Qt::red)
{
vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::yellow));
vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow));
}
}
}
else
{
// Set yellow to indicate we've filtered something (unless red)
if (vorGUI->m_rxIdentItem->foreground().color() != Qt::red)
{
vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::yellow));
vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow));
}
qDebug() << "VORLocalizerGUI::handleMessage: Got MsgReportIdent for non-existant subChannelId " << subChannelId;
}
return true;
@ -938,142 +697,6 @@ void VORLocalizerGUI::handleInputMessages()
}
}
qint64 VORLocalizerGUI::fileAgeInDays(QString filename)
{
QFile file(filename);
if (file.exists())
{
QDateTime modified = file.fileTime(QFileDevice::FileModificationTime);
if (modified.isValid()) {
return modified.daysTo(QDateTime::currentDateTime());
} else {
return -1;
}
}
return -1;
}
bool VORLocalizerGUI::confirmDownload(QString filename)
{
qint64 age = fileAgeInDays(filename);
if ((age == -1) || (age > 100))
{
return true;
}
else
{
QMessageBox::StandardButton reply;
if (age == 0) {
reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded today. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No);
} else if (age == 1) {
reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded yesterday. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No);
} else {
reply = QMessageBox::question(this, "Confirm download", QString("This file was last downloaded %1 days ago. Are you sure you wish to redownload this file?").arg(age), QMessageBox::Yes|QMessageBox::No);
}
return reply == QMessageBox::Yes;
}
}
QString VORLocalizerGUI::getDataDir()
{
// Get directory to store app data in
QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
// First dir is writable
return locations[0];
}
QString VORLocalizerGUI::getOpenAIPVORDBFilename(int i)
{
if (countryCodes[i] != nullptr) {
return getDataDir() + "/" + countryCodes[i] + "_nav.aip";
} else {
return "";
}
}
QString VORLocalizerGUI::getOpenAIPVORDBURL(int i)
{
if (countryCodes[i] != nullptr) {
return QString(OPENAIP_NAVAIDS_URL).arg(countryCodes[i]);
} else {
return "";
}
}
QString VORLocalizerGUI::getVORDBFilename()
{
return getDataDir() + "/vorDatabase.csv";
}
void VORLocalizerGUI::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes)
{
if (m_progressDialog)
{
m_progressDialog->setMaximum(totalBytes);
m_progressDialog->setValue(bytesRead);
}
}
void VORLocalizerGUI::downloadFinished(const QString& filename, bool success)
{
bool closeDialog = true;
if (success)
{
if (filename == getVORDBFilename())
{
m_vors = NavAid::readNavAidsDB(filename);
if (m_vors != nullptr) {
updateVORs();
}
}
else if (filename == getOpenAIPVORDBFilename(m_countryIndex))
{
m_countryIndex++;
if (countryCodes[m_countryIndex] != nullptr)
{
QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex);
QString urlString = getOpenAIPVORDBURL(m_countryIndex);
QUrl dbURL(urlString);
m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString));
m_progressDialog->setValue(m_countryIndex);
m_dlm.download(dbURL, vorDBFile);
closeDialog = false;
}
else
{
readNavAids();
if (m_vors) {
updateVORs();
}
}
}
else
{
qDebug() << "VORLocalizerGUI::downloadFinished: Unexpected filename: " << filename;
}
}
else
{
qDebug() << "VORLocalizerGUI::downloadFinished: Failed: " << filename;
QMessageBox::warning(this, "Download failed", QString("Failed to download %1").arg(filename));
}
if (closeDialog && m_progressDialog)
{
m_progressDialog->close();
delete m_progressDialog;
m_progressDialog = nullptr;
}
}
void VORLocalizerGUI::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
@ -1083,59 +706,56 @@ void VORLocalizerGUI::on_startStop_toggled(bool checked)
}
}
void VORLocalizerGUI::on_getOurAirportsVORDB_clicked()
{
// Don't try to download while already in progress
if (m_progressDialog == nullptr)
{
QString vorDBFile = getVORDBFilename();
if (confirmDownload(vorDBFile))
{
// Download OurAirports navaid database to disk
QUrl dbURL(QString(OURAIRPORTS_NAVAIDS_URL));
m_progressDialog = new QProgressDialog(this);
m_progressDialog->setCancelButton(nullptr);
m_progressDialog->setMinimumDuration(500);
m_progressDialog->setLabelText(QString("Downloading %1.").arg(OURAIRPORTS_NAVAIDS_URL));
QNetworkReply *reply = m_dlm.download(dbURL, vorDBFile);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64)));
}
}
}
void VORLocalizerGUI::on_getOpenAIPVORDB_clicked()
{
// Don't try to download while already in progress
if (!m_progressDialog)
{
m_countryIndex = 0;
QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex);
m_progressDialog = new QProgressDialog(this);
m_progressDialog->setMaximum(OpenAIP::m_countryCodes.size());
m_progressDialog->setCancelButton(nullptr);
if (confirmDownload(vorDBFile))
{
// Download OpenAIP XML to disk
QString urlString = getOpenAIPVORDBURL(m_countryIndex);
QUrl dbURL(urlString);
m_progressDialog = new QProgressDialog(this);
m_progressDialog->setCancelButton(nullptr);
m_progressDialog->setMinimumDuration(500);
m_progressDialog->setMaximum(sizeof(countryCodes)/sizeof(countryCodes[0]));
m_progressDialog->setValue(0);
m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString));
m_dlm.download(dbURL, vorDBFile);
}
m_openAIP.downloadNavAids();
}
}
void VORLocalizerGUI::readNavAids()
{
m_vors = new QHash<int, NavAid *>();
m_vors = OpenAIP::readNavAids();
updateVORs();
}
for (int countryIndex = 0; countryCodes[countryIndex] != nullptr; countryIndex++)
void VORLocalizerGUI::downloadingURL(const QString& url)
{
if (m_progressDialog)
{
QString vorDBFile = getOpenAIPVORDBFilename(countryIndex);
NavAid::readNavAidsXML(m_vors, vorDBFile);
m_progressDialog->setLabelText(QString("Downloading %1.").arg(url));
m_progressDialog->setValue(m_progressDialog->value() + 1);
}
}
void VORLocalizerGUI::downloadError(const QString& error)
{
QMessageBox::critical(this, "VOR Localizer", error);
if (m_progressDialog)
{
m_progressDialog->close();
delete m_progressDialog;
m_progressDialog = nullptr;
}
}
void VORLocalizerGUI::downloadNavAidsFinished()
{
if (m_progressDialog) {
m_progressDialog->setLabelText("Reading NAVAIDs.");
}
readNavAids();
if (m_progressDialog)
{
m_progressDialog->close();
delete m_progressDialog;
m_progressDialog = nullptr;
}
}
@ -1231,7 +851,6 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
m_tickCount(0),
m_progressDialog(nullptr),
m_vorModel(this),
m_vors(nullptr),
m_lastFeatureState(0),
m_rrSecondsCount(0)
{
@ -1250,7 +869,9 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &VORLocalizerGUI::downloadFinished);
connect(&m_openAIP, &OpenAIP::downloadingURL, this, &VORLocalizerGUI::downloadingURL);
connect(&m_openAIP, &OpenAIP::downloadError, this, &VORLocalizerGUI::downloadError);
connect(&m_openAIP, &OpenAIP::downloadNavAidsFinished, this, &VORLocalizerGUI::downloadNavAidsFinished);
m_vorLocalizer = reinterpret_cast<VORLocalizer*>(feature);
m_vorLocalizer->setMessageQueueToGUI(getInputMessageQueue());
@ -1293,22 +914,8 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
}
// Read in VOR information if it exists
bool useOurAirports = false;
if (useOurAirports)
{
m_vors = NavAid::readNavAidsDB(getVORDBFilename());
ui->getOpenAIPVORDB->setVisible(false);
}
else
{
readNavAids();
ui->getOurAirportsVORDB->setVisible(false);
}
if (m_vors) {
updateVORs();
}
readNavAids();
ui->getOurAirportsVORDB->setVisible(false);
// Resize the table using dummy data
resizeTable();
@ -1346,6 +953,7 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
VORLocalizerGUI::~VORLocalizerGUI()
{
delete ui;
qDeleteAll(m_vors);
}
void VORLocalizerGUI::blockApplySettings(bool block)
@ -1459,7 +1067,6 @@ void VORLocalizerGUI::tick()
void VORLocalizerGUI::makeUIConnections()
{
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &VORLocalizerGUI::on_startStop_toggled);
QObject::connect(ui->getOurAirportsVORDB, &QPushButton::clicked, this, &VORLocalizerGUI::on_getOurAirportsVORDB_clicked);
QObject::connect(ui->getOpenAIPVORDB, &QPushButton::clicked, this, &VORLocalizerGUI::on_getOpenAIPVORDB_clicked);
QObject::connect(ui->magDecAdjust, &ButtonSwitch::toggled, this, &VORLocalizerGUI::on_magDecAdjust_toggled);
QObject::connect(ui->rrTime, &QDial::valueChanged, this, &VORLocalizerGUI::on_rrTime_valueChanged);

Wyświetl plik

@ -37,10 +37,10 @@
#include "util/messagequeue.h"
#include "util/httpdownloadmanager.h"
#include "util/azel.h"
#include "util/openaip.h"
#include "settings/rollupstate.h"
#include "vorlocalizersettings.h"
#include "navaid.h"
class PluginAPI;
class FeatureUISet;
@ -239,9 +239,10 @@ private:
QMenu *menu; // Column select context menu
HttpDownloadManager m_dlm;
QProgressDialog *m_progressDialog;
OpenAIP m_openAIP;
int m_countryIndex;
VORModel m_vorModel;
QHash<int, NavAid *> *m_vors;
QList<NavAid *> m_vors;
QHash<int, VORGUI *> m_selectedVORs;
AzEl m_azEl; // Position of station
QIcon m_muteIcon;
@ -264,19 +265,11 @@ private:
void calculateFreqOffset(VORGUI *vorGUI);
void calculateFreqOffsets();
void updateVORs();
QString getOpenAIPVORDBURL(int i);
QString getOpenAIPVORDBFilename(int i);
QString getVORDBFilename();
void readNavAids();
// Move to util
QString getDataDir();
qint64 fileAgeInDays(QString filename);
bool confirmDownload(QString filename);
void updateChannelList();
private slots:
void on_startStop_toggled(bool checked);
void on_getOurAirportsVORDB_clicked();
void on_getOpenAIPVORDB_clicked();
void on_magDecAdjust_toggled(bool checked);
void on_rrTime_valueChanged(int value);
@ -288,11 +281,12 @@ private slots:
void columnSelectMenuChecked(bool checked = false);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void updateDownloadProgress(qint64 bytesRead, qint64 totalBytes);
void downloadFinished(const QString& filename, bool success);
void handleInputMessages();
void updateStatus();
void tick();
void downloadingURL(const QString& url);
void downloadError(const QString& error);
void downloadNavAidsFinished();
};
#endif // INCLUDE_VORLOCALIZERGUI_H

Wyświetl plik

@ -50,7 +50,6 @@ struct SDRBASE_API Airspace {
};
QString m_category; // A-G, GLIDING, DANGER, PROHIBITED, TMZ
int m_id;
QString m_country; // GB
QString m_name; // BIGGIN HILL ATZ 129.405 - TODO: Extract frequency so we can tune to it
AltLimit m_top; // Top of airspace
@ -139,11 +138,7 @@ struct SDRBASE_API Airspace {
while(xmlReader.readNextStartElement())
{
if (xmlReader.name() == QLatin1String("ID"))
{
airspace->m_id = xmlReader.readElementText().toInt();
}
else if (xmlReader.name() == QLatin1String("COUNTRY"))
if (xmlReader.name() == QLatin1String("COUNTRY"))
{
airspace->m_country = xmlReader.readElementText();
}
@ -237,7 +232,7 @@ struct SDRBASE_API Airspace {
};
struct SDRBASE_API NavAid {
int m_id; // Unique ID needed by VOR feature - Don't use value from database as that's 96-bit
QString m_ident; // 2 or 3 character ident
QString m_type; // NDB, VOR, VOR-DME or VORTAC
QString m_name;
@ -258,6 +253,7 @@ struct SDRBASE_API NavAid {
// OpenAIP XML file
static QList<NavAid *> readXML(const QString &filename)
{
int uniqueId = 1;
QList<NavAid *> navAidInfo;
QFile file(filename);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
@ -352,6 +348,7 @@ struct SDRBASE_API NavAid {
}
}
NavAid *navAid = new NavAid();
navAid->m_id = uniqueId++;
navAid->m_ident = id;
// Check idents conform to our filtering rules
if (navAid->m_ident.size() < 2) {