From 14701da1f5c62da764fcb6e5cb90a62774d0e740 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 3 May 2022 13:44:09 +0100 Subject: [PATCH] VOR Localizer: Use shared OpenAIP code to get latest URL --- plugins/feature/vorlocalizer/CMakeLists.txt | 1 - plugins/feature/vorlocalizer/navaid.h | 368 ---------- .../feature/vorlocalizer/vorlocalizergui.cpp | 627 ++++-------------- .../feature/vorlocalizer/vorlocalizergui.h | 18 +- sdrbase/util/openaip.h | 11 +- 5 files changed, 127 insertions(+), 898 deletions(-) delete mode 100644 plugins/feature/vorlocalizer/navaid.h diff --git a/plugins/feature/vorlocalizer/CMakeLists.txt b/plugins/feature/vorlocalizer/CMakeLists.txt index ddf07bb7a..aaf5267bd 100644 --- a/plugins/feature/vorlocalizer/CMakeLists.txt +++ b/plugins/feature/vorlocalizer/CMakeLists.txt @@ -34,7 +34,6 @@ if(NOT SERVER_MODE) set(vor_HEADERS ${vor_HEADERS} vorlocalizergui.h - navaid.h ) set(TARGET_NAME vorlocalizer) diff --git a/plugins/feature/vorlocalizer/navaid.h b/plugins/feature/vorlocalizer/navaid.h deleted file mode 100644 index 1ac7419f6..000000000 --- a/plugins/feature/vorlocalizer/navaid.h +++ /dev/null @@ -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 . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_NAVAID_H -#define INCLUDE_NAVAID_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 *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 *readNavAidsDB(const QString &filename) - { - int cnt = 0; - QHash *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(); - 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 diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.cpp b/plugins/feature/vorlocalizer/vorlocalizergui.cpp index 2e4c0b965..a00085a19 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizergui.cpp @@ -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::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(); + 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(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); diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.h b/plugins/feature/vorlocalizer/vorlocalizergui.h index 0f741c952..51639ad92 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.h +++ b/plugins/feature/vorlocalizer/vorlocalizergui.h @@ -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 *m_vors; + QList m_vors; QHash 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 diff --git a/sdrbase/util/openaip.h b/sdrbase/util/openaip.h index 12434ba82..2c358a22c 100644 --- a/sdrbase/util/openaip.h +++ b/sdrbase/util/openaip.h @@ -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 readXML(const QString &filename) { + int uniqueId = 1; QList 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) {