1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-06-25 13:35:23 -04:00

Merge pull request #1232 from srcejon/v7_vor

VOR Demod and Localizer updates
This commit is contained in:
Edouard Griffiths 2022-05-04 13:34:30 +02:00 committed by GitHub
commit 85f7b1de47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 518 additions and 1213 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

View File

@ -257,6 +257,12 @@ void VORDemod::applySettings(const VORDemodSettings& settings, bool force)
} }
if ((m_settings.m_navId != settings.m_navId) || force) { if ((m_settings.m_navId != settings.m_navId) || force) {
reverseAPIKeys.append("navId"); reverseAPIKeys.append("navId");
// Reset state so we don't report old data for new NavId
m_radial = 0.0f;
m_refMag = -200.0f;
m_varMag = -200.0f;
m_morseIdent = "";
} }
if ((m_settings.m_squelch != settings.m_squelch) || force) { if ((m_settings.m_squelch != settings.m_squelch) || force) {
reverseAPIKeys.append("squelch"); reverseAPIKeys.append("squelch");
@ -509,7 +515,6 @@ void VORDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
double magsqAvg, magsqPeak; double magsqAvg, magsqPeak;
int nbMagsqSamples; int nbMagsqSamples;
getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples); getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
response.getVorDemodReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg)); response.getVorDemodReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg));
response.getVorDemodReport()->setSquelch(m_basebandSink->getSquelchOpen() ? 1 : 0); response.getVorDemodReport()->setSquelch(m_basebandSink->getSquelchOpen() ? 1 : 0);
response.getVorDemodReport()->setAudioSampleRate(m_basebandSink->getAudioSampleRate()); response.getVorDemodReport()->setAudioSampleRate(m_basebandSink->getAudioSampleRate());

View File

@ -401,6 +401,21 @@ void VORDemodSCSink::applySettings(const VORDemodSettings& settings, bool force)
m_squelchLevel = CalcDb::powerFromdB(settings.m_squelch); m_squelchLevel = CalcDb::powerFromdB(settings.m_squelch);
} }
if (m_settings.m_navId != settings.m_navId)
{
// Reset state when navId changes, so we don't report old ident for new navId
m_binSampleCnt = 0;
m_binCnt = 0;
m_identNoise = 0.0001f;
for (int i = 0; i < m_identBins; i++)
{
m_identMaxs[i] = 0.0f;
}
m_ident = "";
m_refGoertzel.reset();
m_varGoertzel.reset();
}
m_settings = settings; m_settings = settings;
} }

View File

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

View File

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

View File

@ -2,7 +2,7 @@
<h2>Introduction</h2> <h2>Introduction</h2>
This plugin can control and receive information from single channel VOR demodulators (see [VOR single channel demodulator](../../channelrx/demodvorsc/readme.md) for details) and collate information from multiple VOR demodulators in order to show your position on a map. This plugin can control and receive information from VOR demodulators (see [VOR demodulator](../../channelrx/demodvor/readme.md) for details) and collate information from multiple VOR demodulators in order to show your position on a map.
<h2>Interface</h2> <h2>Interface</h2>
@ -19,7 +19,7 @@ There are 3 sections in this interface:
<h3>1: Start/Stop plugin</h3> <h3>1: Start/Stop plugin</h3>
This button starts or stops the plugin This button starts or stops the plugin.
<h3>2: Download VOR Database</h3> <h3>2: Download VOR Database</h3>
@ -35,7 +35,7 @@ Available VOR demodulator channels are allocated to service the selected VORs on
<h3>5: Round robin turn time progress</h3> <h3>5: Round robin turn time progress</h3>
Shows the round robin turn time progress Shows the round robin turn time progress.
<h3>6: Force averaging over round robin turn time</h3> <h3>6: Force averaging over round robin turn time</h3>
@ -55,10 +55,6 @@ Channels may be used in round robin turns if their number is not enough to cover
When there is more than one turn for a device valid radial directions are averaged and the resulting average is used during the round robin loop. Averaging also takes place for reference and variable signal levels. When there is more than one turn for a device valid radial directions are averaged and the resulting average is used during the round robin loop. Averaging also takes place for reference and variable signal levels.
<h3>9: Refresh VOR demodulators list and allocation</h3>
Use this button to (re)scan the available VOR demodulators in the SDRangel instance and (re)run the round robin allocation.
<h2>B: VOR Table</h2> <h2>B: VOR Table</h2>
The VOR table displays information about selected VORs. To select or deselect a VOR, double click it on the map. The information displayed includes: The VOR table displays information about selected VORs. To select or deselect a VOR, double click it on the map. The information displayed includes:
@ -67,7 +63,6 @@ The VOR table displays information about selected VORs. To select or deselect a
* Name - The name of the VOR. For example: 'LONDON'. * Name - The name of the VOR. For example: 'LONDON'.
* Freq (MHz) - The center frequency the VOR transmits on in MHz. The frequency is highlighted in green when the VOR is serviced by a demodulator. * Freq (MHz) - The center frequency the VOR transmits on in MHz. The frequency is highlighted in green when the VOR is serviced by a demodulator.
* Nav Id - This is the VOR unique identifier from the VOR database.
* Ident - A 2 or 3 character identifier for the VOR. For example: 'LON'. * Ident - A 2 or 3 character identifier for the VOR. For example: 'LON'.
* Morse - The Morse code identifier for the VOR. For example: '.-.. --- -.' * Morse - The Morse code identifier for the VOR. For example: '.-.. --- -.'
* RX Ident - This contains the demodulated ident. If it matches the expected ident, it will be displayed in green, if not, it will be displayed in red. If an ident is received that is not 2 or 3 characters, it will not be displayed, but the last received ident will be displayed in yellow. * RX Ident - This contains the demodulated ident. If it matches the expected ident, it will be displayed in green, if not, it will be displayed in red. If an ident is received that is not 2 or 3 characters, it will not be displayed, but the last received ident will be displayed in yellow.

View File

@ -47,258 +47,6 @@
#include "vorlocalizersettings.h" #include "vorlocalizersettings.h"
#include "vorlocalizergui.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. // Lats and longs in decimal degrees. Distance in metres. Bearing in degrees.
// https://www.movable-type.co.uk/scripts/latlong.html // https://www.movable-type.co.uk/scripts/latlong.html
static void calcRadialEndPoint(float startLatitude, float startLongitude, float distance, float bearing, float &endLatitude, float &endLongitude) static void calcRadialEndPoint(float startLatitude, float startLongitude, float distance, float bearing, float &endLatitude, float &endLongitude)
@ -389,7 +137,6 @@ VORGUI::VORGUI(NavAid *navAid, VORLocalizerGUI *gui) :
// These are deleted by QTableWidget // These are deleted by QTableWidget
m_nameItem = new QTableWidgetItem(); m_nameItem = new QTableWidgetItem();
m_frequencyItem = new QTableWidgetItem(); m_frequencyItem = new QTableWidgetItem();
m_navIdItem = new QTableWidgetItem();
m_radialItem = new QTableWidgetItem(); m_radialItem = new QTableWidgetItem();
m_identItem = new QTableWidgetItem(); m_identItem = new QTableWidgetItem();
m_morseItem = new QTableWidgetItem(); m_morseItem = new QTableWidgetItem();
@ -610,7 +357,6 @@ void VORLocalizerGUI::resizeTable()
ui->vorData->setRowCount(row + 1); ui->vorData->setRowCount(row + 1);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAME, new QTableWidgetItem("White Sulphur Springs")); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAME, new QTableWidgetItem("White Sulphur Springs"));
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_FREQUENCY, new QTableWidgetItem("Freq (MHz) ")); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_FREQUENCY, new QTableWidgetItem("Freq (MHz) "));
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAVID, new QTableWidgetItem("99999999"));
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_IDENT, new QTableWidgetItem("Ident ")); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_IDENT, new QTableWidgetItem("Ident "));
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse))); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse)));
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, new QTableWidgetItem("Radial (o) ")); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, new QTableWidgetItem("Radial (o) "));
@ -684,7 +430,6 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
ui->vorData->setRowCount(row + 1); ui->vorData->setRowCount(row + 1);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAME, vorGUI->m_nameItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAME, vorGUI->m_nameItem);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_FREQUENCY, vorGUI->m_frequencyItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_FREQUENCY, vorGUI->m_frequencyItem);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAVID, vorGUI->m_navIdItem);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_IDENT, vorGUI->m_identItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_IDENT, vorGUI->m_identItem);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_MORSE, vorGUI->m_morseItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_MORSE, vorGUI->m_morseItem);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, vorGUI->m_radialItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, vorGUI->m_radialItem);
@ -702,7 +447,7 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
// Add to settings to create corresponding demodulator // Add to settings to create corresponding demodulator
m_settings.m_subChannelSettings.insert(navId, VORLocalizerSubChannelSettings{ m_settings.m_subChannelSettings.insert(navId, VORLocalizerSubChannelSettings{
navId, navId,
vorGUI->m_navAid->m_frequencykHz * 1000, (int)(vorGUI->m_navAid->m_frequencykHz * 1000),
false false
}); });
@ -725,13 +470,12 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
void VORLocalizerGUI::updateVORs() void VORLocalizerGUI::updateVORs()
{ {
m_vorModel.removeAllVORs(); m_vorModel.removeAllVORs();
QHash<int, NavAid *>::iterator i = m_vors->begin();
AzEl azEl = m_azEl; AzEl azEl = m_azEl;
while (i != m_vors->end()) for (auto vor : m_vors)
{
if (vor->m_type.contains("VOR")) // Exclude DMEs
{ {
NavAid *vor = i.value();
// Calculate distance to VOR from My Position // Calculate distance to VOR from My Position
azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation)); azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation));
azEl.calculate(); azEl.calculate();
@ -740,8 +484,7 @@ void VORLocalizerGUI::updateVORs()
if (azEl.getDistance() <= 200000) { if (azEl.getDistance() <= 200000) {
m_vorModel.addVOR(vor); m_vorModel.addVOR(vor);
} }
}
++i;
} }
} }
@ -807,7 +550,8 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
int subChannelId = report.getSubChannelId(); int subChannelId = report.getSubChannelId();
VORGUI *vorGUI = m_selectedVORs.value(subChannelId); 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 varMagDB = std::round(20.0*std::log10(report.getVarMag()));
@ -815,7 +559,6 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
bool validRadial = report.getValidRadial(); bool validRadial = report.getValidRadial();
vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial())); vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial()));
vorGUI->m_navIdItem->setData(Qt::DisplayRole, subChannelId);
if (validRadial) { if (validRadial) {
vorGUI->m_radialItem->setForeground(QBrush(Qt::white)); vorGUI->m_radialItem->setForeground(QBrush(Qt::white));
@ -841,6 +584,11 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
// Update radial on map // Update radial on map
m_vorModel.setRadial(subChannelId, validRadial, report.getRadial()); m_vorModel.setRadial(subChannelId, validRadial, report.getRadial());
}
else
{
qDebug() << "VORLocalizerGUI::handleMessage: Got MsgReportRadial for non-existant subChannelId " << subChannelId;
}
return true; return true;
} }
@ -850,6 +598,8 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
int subChannelId = report.getSubChannelId(); int subChannelId = report.getSubChannelId();
VORGUI *vorGUI = m_selectedVORs.value(subChannelId); VORGUI *vorGUI = m_selectedVORs.value(subChannelId);
if (vorGUI)
{
QString ident = report.getIdent(); QString ident = report.getIdent();
// Convert Morse to a string // Convert Morse to a string
@ -883,6 +633,11 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow)); vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow));
} }
} }
}
else
{
qDebug() << "VORLocalizerGUI::handleMessage: Got MsgReportIdent for non-existant subChannelId " << subChannelId;
}
return true; return true;
} }
@ -938,168 +693,17 @@ 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) void VORLocalizerGUI::on_startStop_toggled(bool checked)
{ {
if (m_doApplySettings) if (m_doApplySettings)
{ {
VORLocalizer::MsgStartStop *message = VORLocalizer::MsgStartStop::create(checked); VORLocalizer::MsgStartStop *message = VORLocalizer::MsgStartStop::create(checked);
m_vorLocalizer->getInputMessageQueue()->push(message); m_vorLocalizer->getInputMessageQueue()->push(message);
}
}
void VORLocalizerGUI::on_getOurAirportsVORDB_clicked() if (checked)
{ {
// Don't try to download while already in progress // Refresh channels in case device b/w has changed
if (m_progressDialog == nullptr) channelsRefresh();
{
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)));
} }
} }
} }
@ -1109,33 +713,51 @@ void VORLocalizerGUI::on_getOpenAIPVORDB_clicked()
// Don't try to download while already in progress // Don't try to download while already in progress
if (!m_progressDialog) if (!m_progressDialog)
{ {
m_countryIndex = 0;
QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex);
if (confirmDownload(vorDBFile))
{
// Download OpenAIP XML to disk
QString urlString = getOpenAIPVORDBURL(m_countryIndex);
QUrl dbURL(urlString);
m_progressDialog = new QProgressDialog(this); m_progressDialog = new QProgressDialog(this);
m_progressDialog->setMaximum(OpenAIP::m_countryCodes.size());
m_progressDialog->setCancelButton(nullptr); m_progressDialog->setCancelButton(nullptr);
m_progressDialog->setMinimumDuration(500);
m_progressDialog->setMaximum(sizeof(countryCodes)/sizeof(countryCodes[0])); m_openAIP.downloadNavAids();
m_progressDialog->setValue(0);
m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString));
m_dlm.download(dbURL, vorDBFile);
}
} }
} }
void VORLocalizerGUI::readNavAids() 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)
{ {
QString vorDBFile = getOpenAIPVORDBFilename(countryIndex); if (m_progressDialog)
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;
} }
} }
@ -1160,7 +782,7 @@ void VORLocalizerGUI::on_centerShift_valueChanged(int value)
applySettings(); applySettings();
} }
void VORLocalizerGUI::on_channelsRefresh_clicked() void VORLocalizerGUI::channelsRefresh()
{ {
if (m_doApplySettings) if (m_doApplySettings)
{ {
@ -1231,7 +853,6 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
m_tickCount(0), m_tickCount(0),
m_progressDialog(nullptr), m_progressDialog(nullptr),
m_vorModel(this), m_vorModel(this),
m_vors(nullptr),
m_lastFeatureState(0), m_lastFeatureState(0),
m_rrSecondsCount(0) m_rrSecondsCount(0)
{ {
@ -1250,7 +871,9 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off); m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); 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 = reinterpret_cast<VORLocalizer*>(feature);
m_vorLocalizer->setMessageQueueToGUI(getInputMessageQueue()); m_vorLocalizer->setMessageQueueToGUI(getInputMessageQueue());
@ -1293,22 +916,7 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
} }
// Read in VOR information if it exists // Read in VOR information if it exists
bool useOurAirports = false;
if (useOurAirports)
{
m_vors = NavAid::readNavAidsDB(getVORDBFilename());
ui->getOpenAIPVORDB->setVisible(false);
}
else
{
readNavAids(); readNavAids();
ui->getOurAirportsVORDB->setVisible(false);
}
if (m_vors) {
updateVORs();
}
// Resize the table using dummy data // Resize the table using dummy data
resizeTable(); resizeTable();
@ -1338,14 +946,33 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
ui->rrTurnTimeProgress->setValue(0); ui->rrTurnTimeProgress->setValue(0);
ui->rrTurnTimeProgress->setToolTip(tr("Round robin turn time %1s").arg(0)); ui->rrTurnTimeProgress->setToolTip(tr("Round robin turn time %1s").arg(0));
// Get updated when position changes
connect(&MainCore::instance()->getSettings(), &MainSettings::preferenceChanged, this, &VORLocalizerGUI::preferenceChanged);
displaySettings(); displaySettings();
applySettings(true); applySettings(true);
connect(&m_redrawMapTimer, &QTimer::timeout, this, &VORLocalizerGUI::redrawMap);
m_redrawMapTimer.setSingleShot(true);
ui->map->installEventFilter(this);
makeUIConnections(); makeUIConnections();
// Update channel list when added/removed
connect(MainCore::instance(), &MainCore::channelAdded, this, &VORLocalizerGUI::channelsRefresh);
connect(MainCore::instance(), &MainCore::channelRemoved, this, &VORLocalizerGUI::channelsRefresh);
// Also replan when device changed (as bandwidth may change or may becomed fixed center freq)
connect(MainCore::instance(), &MainCore::deviceChanged, this, &VORLocalizerGUI::channelsRefresh);
// List already opened channels
channelsRefresh();
} }
VORLocalizerGUI::~VORLocalizerGUI() VORLocalizerGUI::~VORLocalizerGUI()
{ {
disconnect(&m_redrawMapTimer, &QTimer::timeout, this, &VORLocalizerGUI::redrawMap);
m_redrawMapTimer.stop();
delete ui; delete ui;
qDeleteAll(m_vors);
} }
void VORLocalizerGUI::blockApplySettings(bool block) void VORLocalizerGUI::blockApplySettings(bool block)
@ -1456,13 +1083,107 @@ void VORLocalizerGUI::tick()
} }
} }
void VORLocalizerGUI::preferenceChanged(int elementType)
{
Preferences::ElementType pref = (Preferences::ElementType)elementType;
if ((pref == Preferences::Latitude) || (pref == Preferences::Longitude) || (pref == Preferences::Altitude))
{
Real stationLatitude = MainCore::instance()->getSettings().getLatitude();
Real stationLongitude = MainCore::instance()->getSettings().getLongitude();
Real stationAltitude = MainCore::instance()->getSettings().getAltitude();
if ( (stationLatitude != m_azEl.getLocationSpherical().m_latitude)
|| (stationLongitude != m_azEl.getLocationSpherical().m_longitude)
|| (stationAltitude != m_azEl.getLocationSpherical().m_altitude))
{
m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude);
// Update distances and what is visible
updateVORs();
// Update icon position on Map
QQuickItem *item = ui->map->rootObject();
QObject *map = item->findChild<QObject*>("map");
if (map != nullptr)
{
QObject *stationObject = map->findChild<QObject*>("station");
if(stationObject != NULL)
{
QGeoCoordinate coords = stationObject->property("coordinate").value<QGeoCoordinate>();
coords.setLatitude(stationLatitude);
coords.setLongitude(stationLongitude);
coords.setAltitude(stationAltitude);
stationObject->setProperty("coordinate", QVariant::fromValue(coords));
}
}
}
}
if (pref == Preferences::StationName)
{
// Update icon label on Map
QQuickItem *item = ui->map->rootObject();
QObject *map = item->findChild<QObject*>("map");
if (map != nullptr)
{
QObject *stationObject = map->findChild<QObject*>("station");
if(stationObject != NULL) {
stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName()));
}
}
}
}
void VORLocalizerGUI::redrawMap()
{
// An awful workaround for https://bugreports.qt.io/browse/QTBUG-100333
// Also used in ADS-B demod
QQuickItem *item = ui->map->rootObject();
if (item)
{
QObject *object = item->findChild<QObject*>("map");
if (object)
{
double zoom = object->property("zoomLevel").value<double>();
object->setProperty("zoomLevel", QVariant::fromValue(zoom+1));
object->setProperty("zoomLevel", QVariant::fromValue(zoom));
}
}
}
void VORLocalizerGUI::showEvent(QShowEvent *event)
{
if (!event->spontaneous())
{
// Workaround for https://bugreports.qt.io/browse/QTBUG-100333
// MapQuickItems can be in wrong position when window is first displayed
m_redrawMapTimer.start(500);
}
}
bool VORLocalizerGUI::eventFilter(QObject *obj, QEvent *event)
{
if (obj == ui->map)
{
if (event->type() == QEvent::Resize)
{
// Workaround for https://bugreports.qt.io/browse/QTBUG-100333
// MapQuickItems can be in wrong position after vertical resize
QResizeEvent *resizeEvent = static_cast<QResizeEvent *>(event);
QSize oldSize = resizeEvent->oldSize();
QSize size = resizeEvent->size();
if (oldSize.height() != size.height()) {
redrawMap();
}
}
}
return false;
}
void VORLocalizerGUI::makeUIConnections() void VORLocalizerGUI::makeUIConnections()
{ {
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &VORLocalizerGUI::on_startStop_toggled); 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->getOpenAIPVORDB, &QPushButton::clicked, this, &VORLocalizerGUI::on_getOpenAIPVORDB_clicked);
QObject::connect(ui->magDecAdjust, &ButtonSwitch::toggled, this, &VORLocalizerGUI::on_magDecAdjust_toggled); QObject::connect(ui->magDecAdjust, &ButtonSwitch::toggled, this, &VORLocalizerGUI::on_magDecAdjust_toggled);
QObject::connect(ui->rrTime, &QDial::valueChanged, this, &VORLocalizerGUI::on_rrTime_valueChanged); QObject::connect(ui->rrTime, &QDial::valueChanged, this, &VORLocalizerGUI::on_rrTime_valueChanged);
QObject::connect(ui->centerShift, &QDial::valueChanged, this, &VORLocalizerGUI::on_centerShift_valueChanged); QObject::connect(ui->centerShift, &QDial::valueChanged, this, &VORLocalizerGUI::on_centerShift_valueChanged);
QObject::connect(ui->channelsRefresh, &QPushButton::clicked, this, &VORLocalizerGUI::on_channelsRefresh_clicked);
} }

View File

@ -37,10 +37,10 @@
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "util/httpdownloadmanager.h" #include "util/httpdownloadmanager.h"
#include "util/azel.h" #include "util/azel.h"
#include "util/openaip.h"
#include "settings/rollupstate.h" #include "settings/rollupstate.h"
#include "vorlocalizersettings.h" #include "vorlocalizersettings.h"
#include "navaid.h"
class PluginAPI; class PluginAPI;
class FeatureUISet; class FeatureUISet;
@ -64,7 +64,6 @@ public:
QTableWidgetItem *m_nameItem; QTableWidgetItem *m_nameItem;
QTableWidgetItem *m_frequencyItem; QTableWidgetItem *m_frequencyItem;
QTableWidgetItem *m_navIdItem;
QTableWidgetItem *m_identItem; QTableWidgetItem *m_identItem;
QTableWidgetItem *m_morseItem; QTableWidgetItem *m_morseItem;
QTableWidgetItem *m_radialItem; QTableWidgetItem *m_radialItem;
@ -239,15 +238,17 @@ private:
QMenu *menu; // Column select context menu QMenu *menu; // Column select context menu
HttpDownloadManager m_dlm; HttpDownloadManager m_dlm;
QProgressDialog *m_progressDialog; QProgressDialog *m_progressDialog;
OpenAIP m_openAIP;
int m_countryIndex; int m_countryIndex;
VORModel m_vorModel; VORModel m_vorModel;
QHash<int, NavAid *> *m_vors; QList<NavAid *> m_vors;
QHash<int, VORGUI *> m_selectedVORs; QHash<int, VORGUI *> m_selectedVORs;
AzEl m_azEl; // Position of station AzEl m_azEl; // Position of station
QIcon m_muteIcon; QIcon m_muteIcon;
QTimer m_statusTimer; QTimer m_statusTimer;
int m_lastFeatureState; int m_lastFeatureState;
int m_rrSecondsCount; int m_rrSecondsCount;
QTimer m_redrawMapTimer;
explicit VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); explicit VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
virtual ~VORLocalizerGUI(); virtual ~VORLocalizerGUI();
@ -256,6 +257,7 @@ private:
void applySettings(bool force = false); void applySettings(bool force = false);
void displaySettings(); void displaySettings();
bool handleMessage(const Message& message); bool handleMessage(const Message& message);
void redrawMap();
void makeUIConnections(); void makeUIConnections();
void resizeTable(); void resizeTable();
@ -264,35 +266,31 @@ private:
void calculateFreqOffset(VORGUI *vorGUI); void calculateFreqOffset(VORGUI *vorGUI);
void calculateFreqOffsets(); void calculateFreqOffsets();
void updateVORs(); void updateVORs();
QString getOpenAIPVORDBURL(int i);
QString getOpenAIPVORDBFilename(int i);
QString getVORDBFilename();
void readNavAids(); void readNavAids();
// Move to util
QString getDataDir();
qint64 fileAgeInDays(QString filename);
bool confirmDownload(QString filename);
void updateChannelList(); void updateChannelList();
private slots: private slots:
void on_startStop_toggled(bool checked); void on_startStop_toggled(bool checked);
void on_getOurAirportsVORDB_clicked();
void on_getOpenAIPVORDB_clicked(); void on_getOpenAIPVORDB_clicked();
void on_magDecAdjust_toggled(bool checked); void on_magDecAdjust_toggled(bool checked);
void on_rrTime_valueChanged(int value); void on_rrTime_valueChanged(int value);
void on_centerShift_valueChanged(int value); void on_centerShift_valueChanged(int value);
void on_channelsRefresh_clicked(); void channelsRefresh();
void vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex); void vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
void vorData_sectionResized(int logicalIndex, int oldSize, int newSize); void vorData_sectionResized(int logicalIndex, int oldSize, int newSize);
void columnSelectMenu(QPoint pos); void columnSelectMenu(QPoint pos);
void columnSelectMenuChecked(bool checked = false); void columnSelectMenuChecked(bool checked = false);
void onWidgetRolled(QWidget* widget, bool rollDown); void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p); void onMenuDialogCalled(const QPoint& p);
void updateDownloadProgress(qint64 bytesRead, qint64 totalBytes);
void downloadFinished(const QString& filename, bool success);
void handleInputMessages(); void handleInputMessages();
void updateStatus(); void updateStatus();
void tick(); void tick();
void downloadingURL(const QString& url);
void downloadError(const QString& error);
void downloadNavAidsFinished();
void preferenceChanged(int elementType);
virtual void showEvent(QShowEvent *event);
virtual bool eventFilter(QObject *obj, QEvent *event);
}; };
#endif // INCLUDE_VORLOCALIZERGUI_H #endif // INCLUDE_VORLOCALIZERGUI_H

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>462</width> <width>470</width>
<height>850</height> <height>850</height>
</rect> </rect>
</property> </property>
@ -40,7 +40,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>461</width> <width>461</width>
<height>61</height> <height>31</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -85,23 +85,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="getOurAirportsVORDB">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Download OurAirports VOR database</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/demodvor/icons/vor.png</normaloff>:/demodvor/icons/vor.png</iconset>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="getOpenAIPVORDB"> <widget class="QPushButton" name="getOpenAIPVORDB">
<property name="toolTip"> <property name="toolTip">
@ -136,6 +119,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="rrTimeLabel"> <widget class="QLabel" name="rrTimeLabel">
<property name="text"> <property name="text">
@ -180,7 +170,7 @@
</size> </size>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Sound volume (%)</string> <string>Round robin turn time (s)</string>
</property> </property>
<property name="text"> <property name="text">
<string>20s</string> <string>20s</string>
@ -223,10 +213,17 @@ QToolTip{background-color: white; color: black;}</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="centerShiftLabel"> <widget class="QLabel" name="centerShiftLabel">
<property name="text"> <property name="text">
<string>Sh</string> <string>Δcf</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -275,22 +272,12 @@ QToolTip{background-color: white; color: black;}</string>
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer_2"> <widget class="Line" name="line">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeHint" stdset="0"> </widget>
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item> </item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="vorsLayout">
<item> <item>
<widget class="QLabel" name="channelsLabel"> <widget class="QLabel" name="channelsLabel">
<property name="text"> <property name="text">
@ -306,27 +293,7 @@ QToolTip{background-color: white; color: black;}</string>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="channelsRefresh"> <spacer name="horizontalSpacer_2">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Refresh VOR channels available</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
@ -345,14 +312,14 @@ QToolTip{background-color: white; color: black;}</string>
<widget class="QWidget" name="dataContainer" native="true"> <widget class="QWidget" name="dataContainer" native="true">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>10</x>
<y>110</y> <y>50</y>
<width>461</width> <width>441</width>
<height>145</height> <height>710</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -366,24 +333,37 @@ QToolTip{background-color: white; color: black;}</string>
<property name="windowTitle"> <property name="windowTitle">
<string>VORs</string> <string>VORs</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayoutTable"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin"> <property name="leftMargin">
<number>3</number> <number>0</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>3</number> <number>0</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>3</number> <number>0</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>3</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTableWidget" name="vorData"> <widget class="QTableWidget" name="vorData">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="editTriggers"> <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set> <set>QAbstractItemView::NoEditTriggers</set>
</property> </property>
@ -403,14 +383,6 @@ QToolTip{background-color: white; color: black;}</string>
<string>Frequency of the VOR in MHz</string> <string>Frequency of the VOR in MHz</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>Nav Id</string>
</property>
<property name="toolTip">
<string>Offset of the VOR's frequency from the current center frequency. Red indicates out of range.</string>
</property>
</column>
<column> <column>
<property name="text"> <property name="text">
<string>Ident</string> <string>Ident</string>
@ -476,49 +448,11 @@ QToolTip{background-color: white; color: black;}</string>
</property> </property>
</column> </column>
</widget> </widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="mapContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>258</y>
<width>461</width>
<height>581</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Map</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutMap" stretch="0">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QQuickWidget" name="map"> <widget class="QQuickWidget" name="map">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>4</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -539,6 +473,7 @@ QToolTip{background-color: white; color: black;}</string>
</url> </url>
</property> </property>
</widget> </widget>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -562,9 +497,7 @@ QToolTip{background-color: white; color: black;}</string>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>getOurAirportsVORDB</tabstop>
<tabstop>vorData</tabstop> <tabstop>vorData</tabstop>
<tabstop>map</tabstop>
</tabstops> </tabstops>
<resources> <resources>
<include location="../../../sdrgui/resources/res.qrc"/> <include location="../../../sdrgui/resources/res.qrc"/>

View File

@ -77,18 +77,17 @@ struct VORLocalizerSettings
int m_workspaceIndex; int m_workspaceIndex;
QByteArray m_geometryBytes; QByteArray m_geometryBytes;
static const int VORDEMOD_COLUMNS = 11; static const int VORDEMOD_COLUMNS = 10;
static const int VOR_COL_NAME = 0; static const int VOR_COL_NAME = 0;
static const int VOR_COL_FREQUENCY = 1; static const int VOR_COL_FREQUENCY = 1;
static const int VOR_COL_NAVID = 2; static const int VOR_COL_IDENT = 2;
static const int VOR_COL_IDENT = 3; static const int VOR_COL_MORSE = 3;
static const int VOR_COL_MORSE = 4; static const int VOR_COL_RX_IDENT = 4;
static const int VOR_COL_RX_IDENT = 5; static const int VOR_COL_RX_MORSE = 5;
static const int VOR_COL_RX_MORSE = 6; static const int VOR_COL_RADIAL = 6;
static const int VOR_COL_RADIAL = 7; static const int VOR_COL_REF_MAG = 7;
static const int VOR_COL_REF_MAG = 8; static const int VOR_COL_VAR_MAG = 8;
static const int VOR_COL_VAR_MAG = 9; static const int VOR_COL_MUTE = 9;
static const int VOR_COL_MUTE = 10;
int m_columnIndexes[VORDEMOD_COLUMNS];//!< How the columns are ordered in the table int m_columnIndexes[VORDEMOD_COLUMNS];//!< How the columns are ordered in the table
int m_columnSizes[VORDEMOD_COLUMNS]; //!< Size of the coumns in the table int m_columnSizes[VORDEMOD_COLUMNS]; //!< Size of the coumns in the table

View File

@ -24,7 +24,11 @@
#include "SWGErrorResponse.h" #include "SWGErrorResponse.h"
#include "device/deviceset.h" #include "device/deviceset.h"
#include "device/deviceapi.h"
#include "dsp/devicesamplesource.h"
#include "dsp/devicesamplesink.h"
#include "channel/channelapi.h" #include "channel/channelapi.h"
#include "channel/channelwebapiutils.h"
#include "webapi/webapiadapterinterface.h" #include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h" #include "webapi/webapiutils.h"
#include "maincore.h" #include "maincore.h"
@ -78,6 +82,7 @@ void VorLocalizerWorker::started()
m_rrTimer.start(m_settings.m_rrTime * 1000); m_rrTimer.start(m_settings.m_rrTime * 1000);
disconnect(thread(), SIGNAL(started()), this, SLOT(started())); disconnect(thread(), SIGNAL(started()), this, SLOT(started()));
} }
void VorLocalizerWorker::stopWork() void VorLocalizerWorker::stopWork()
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
@ -205,6 +210,53 @@ void VorLocalizerWorker::updateHardware()
m_mutex.unlock(); m_mutex.unlock();
} }
quint64 VorLocalizerWorker::getDeviceCenterFrequency(int deviceIndex)
{
std::vector<DeviceSet*> deviceSets = MainCore::instance()->getDeviceSets();
if (deviceIndex < deviceSets.size())
{
DeviceSet *deviceSet = deviceSets[deviceIndex];
if (deviceSet->m_deviceSourceEngine)
{
DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
return source->getCenterFrequency();
}
else if (deviceSet->m_deviceSinkEngine)
{
DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink();
return sink->getCenterFrequency();
}
}
return 0;
}
int VorLocalizerWorker::getDeviceSampleRate(int deviceIndex)
{
std::vector<DeviceSet*> deviceSets = MainCore::instance()->getDeviceSets();
if (deviceIndex < deviceSets.size())
{
DeviceSet *deviceSet = deviceSets[deviceIndex];
if (deviceSet->m_deviceSourceEngine)
{
DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
return source->getSampleRate();
}
else if (deviceSet->m_deviceSinkEngine)
{
DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink();
return sink->getSampleRate();
}
}
return 0;
}
// Does this device have a center frequency setting (FileInput doesn't)
bool VorLocalizerWorker::hasCenterFrequencySetting(int deviceIndex)
{
double deviceFrequency;
return !ChannelWebAPIUtils::getCenterFrequency(deviceIndex, deviceFrequency);
}
void VorLocalizerWorker::removeVORChannel(int navId) void VorLocalizerWorker::removeVORChannel(int navId)
{ {
qDebug("VorLocalizerWorker::removeVORChannel: %d", navId); qDebug("VorLocalizerWorker::removeVORChannel: %d", navId);
@ -294,7 +346,12 @@ void VorLocalizerWorker::updateChannels()
RRTurnPlan turnPlan(deviceChannel); RRTurnPlan turnPlan(deviceChannel);
int fMin = vorList.front().m_frequency; int fMin = vorList.front().m_frequency;
int fMax = vorList.back().m_frequency; int fMax = vorList.back().m_frequency;
int devFreq = (fMin + fMax) / 2; int devFreq;
if (turnPlan.m_fixedCenterFrequency) {
devFreq = getDeviceCenterFrequency(turnPlan.m_device.m_deviceIndex);
} else {
devFreq = (fMin + fMax) / 2;
}
turnPlan.m_device.m_frequency = devFreq; turnPlan.m_device.m_frequency = devFreq;
int iCh = 0; int iCh = 0;
@ -321,7 +378,6 @@ void VorLocalizerWorker::updateChannels()
++it; ++it;
} }
} }
iCh++; iCh++;
} }
@ -359,7 +415,12 @@ void VorLocalizerWorker::updateChannels()
RRTurnPlan turnPlan(deviceChannel); RRTurnPlan turnPlan(deviceChannel);
int fMin = vorList.front().m_frequency; int fMin = vorList.front().m_frequency;
int fMax = vorList.back().m_frequency; int fMax = vorList.back().m_frequency;
int devFreq = (fMin + fMax) / 2; int devFreq;
if (turnPlan.m_fixedCenterFrequency) {
devFreq = getDeviceCenterFrequency(turnPlan.m_device.m_deviceIndex);
} else {
devFreq = (fMin + fMax) / 2;
}
turnPlan.m_device.m_frequency = devFreq; turnPlan.m_device.m_frequency = devFreq;
int iCh = 0; int iCh = 0;
@ -406,69 +467,6 @@ void VorLocalizerWorker::updateChannels()
rrNextTurn(); rrNextTurn();
} }
void VorLocalizerWorker::allocateChannel(ChannelAPI *channel, int vorFrequency, int vorNavId, int channelShift)
{
VORLocalizerSettings::AvailableChannel& availableChannel = m_availableChannels->operator[](channel);
qDebug() << "VorLocalizerWorker::allocateChannel:"
<< " vorNavId:" << vorNavId
<< " vorFrequency:" << vorFrequency
<< " channelShift:" << channelShift
<< " deviceIndex:" << availableChannel.m_deviceSetIndex
<< " channelIndex:" << availableChannel.m_channelIndex;
double deviceFrequency = vorFrequency - channelShift;
setDeviceFrequency(availableChannel.m_deviceSetIndex, deviceFrequency);
setChannelShift(availableChannel.m_deviceSetIndex, availableChannel.m_channelIndex, channelShift, vorNavId);
availableChannel.m_navId = vorNavId;
}
void VorLocalizerWorker::setDeviceFrequency(int deviceIndex, double targetFrequency)
{
SWGSDRangel::SWGDeviceSettings deviceSettingsResponse;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC;
// Get current device center frequency
httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsGet(
deviceIndex,
deviceSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("VorLocalizerWorker::setDeviceFrequency: get device frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
}
QJsonObject *jsonObj = deviceSettingsResponse.asJsonObject();
// Update centerFrequency
WebAPIUtils::setSubObjectDouble(*jsonObj, "centerFrequency", targetFrequency);
QStringList deviceSettingsKeys;
deviceSettingsKeys.append("centerFrequency");
deviceSettingsResponse.init();
deviceSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsPutPatch(
deviceIndex,
false, // PATCH
deviceSettingsKeys,
deviceSettingsResponse,
errorResponse2
);
if (httpRC/100 == 2)
{
qDebug("VorLocalizerWorker::setDeviceFrequency: set device frequency %f OK", targetFrequency);
}
else
{
qWarning("VorLocalizerWorker::setDeviceFrequency: set device frequency error %d: %s",
httpRC, qPrintable(*errorResponse2.getMessage()));
}
}
void VorLocalizerWorker::setChannelShift(int deviceIndex, int channelIndex, double targetOffset, int vorNavId) void VorLocalizerWorker::setChannelShift(int deviceIndex, int channelIndex, double targetOffset, int vorNavId)
{ {
SWGSDRangel::SWGChannelSettings channelSettingsResponse; SWGSDRangel::SWGChannelSettings channelSettingsResponse;
@ -674,14 +672,16 @@ void VorLocalizerWorker::getChannelsByDevice(
for (; itr != availableChannels->end(); ++itr) for (; itr != availableChannels->end(); ++itr)
{ {
devicesChannelsMap[itr->m_deviceSetIndex].m_device.m_deviceIndex = itr->m_deviceSetIndex; devicesChannelsMap[itr->m_deviceSetIndex].m_device.m_deviceIndex = itr->m_deviceSetIndex;
devicesChannelsMap[itr->m_deviceSetIndex].m_bandwidth = itr->m_basebandSampleRate; devicesChannelsMap[itr->m_deviceSetIndex].m_bandwidth = getDeviceSampleRate(itr->m_deviceSetIndex); // Get b/w of device, not channel, as the latter may be decimated
devicesChannelsMap[itr->m_deviceSetIndex].m_channels.push_back(RRChannel{itr->m_channelAPI, itr->m_channelIndex, 0, -1}); devicesChannelsMap[itr->m_deviceSetIndex].m_channels.push_back(RRChannel{itr->m_channelAPI, itr->m_channelIndex, 0, -1});
} }
QMap<int, RRTurnPlan>::const_iterator itm = devicesChannelsMap.begin(); QMap<int, RRTurnPlan>::iterator itm = devicesChannelsMap.begin();
devicesChannels.clear(); devicesChannels.clear();
for (; itm != devicesChannelsMap.end(); ++itm) { for (; itm != devicesChannelsMap.end(); ++itm)
{
itm->m_fixedCenterFrequency = hasCenterFrequencySetting(itm->m_device.m_deviceIndex);
devicesChannels.push_back(*itm); devicesChannels.push_back(*itm);
} }
@ -700,23 +700,32 @@ void VorLocalizerWorker::rrNextTurn()
unsigned int turnCount = m_rrTurnCounters[iDevPlan]; unsigned int turnCount = m_rrTurnCounters[iDevPlan];
int deviceIndex = rrPlan[turnCount].m_device.m_deviceIndex; int deviceIndex = rrPlan[turnCount].m_device.m_deviceIndex;
int deviceFrequency = rrPlan[turnCount].m_device.m_frequency - m_settings.m_centerShift; int deviceFrequency = rrPlan[turnCount].m_device.m_frequency - m_settings.m_centerShift;
qDebug() << "VorLocalizerWorker::rrNextTurn: " qDebug() << "VorLocalizerWorker::rrNextTurn: "
<< "turn:" << turnCount << "turn:" << turnCount
<< "device:" << deviceIndex << "device:" << deviceIndex
<< "frequency:" << deviceFrequency - m_settings.m_centerShift; << "frequency:" << deviceFrequency - m_settings.m_centerShift;
setDeviceFrequency(deviceIndex, deviceFrequency);
if (!rrPlan[turnCount].m_fixedCenterFrequency) {
ChannelWebAPIUtils::setCenterFrequency(deviceIndex, deviceFrequency);
}
for (auto channel : rrPlan[turnCount].m_channels) for (auto channel : rrPlan[turnCount].m_channels)
{ {
int shift = channel.m_frequencyShift;
if (!rrPlan[turnCount].m_fixedCenterFrequency) {
shift += m_settings.m_centerShift;
}
qDebug() << "VorLocalizerWorker::rrNextTurn: " qDebug() << "VorLocalizerWorker::rrNextTurn: "
<< "device:" << deviceIndex << "device:" << deviceIndex
<< "channel:" << channel.m_channelIndex << "channel:" << channel.m_channelIndex
<< "shift:" << channel.m_frequencyShift + m_settings.m_centerShift << "shift:" << shift
<< "navId:" << channel.m_navId; << "navId:" << channel.m_navId;
setChannelShift( setChannelShift(
deviceIndex, deviceIndex,
channel.m_channelIndex, channel.m_channelIndex,
channel.m_frequencyShift + m_settings.m_centerShift, shift,
channel.m_navId channel.m_navId
); );
m_channelAllocations[channel.m_navId] = ChannelAllocation{ m_channelAllocations[channel.m_navId] = ChannelAllocation{

View File

@ -121,6 +121,7 @@ private:
RRDevice m_device; RRDevice m_device;
int m_bandwidth; int m_bandwidth;
std::vector<RRChannel> m_channels; std::vector<RRChannel> m_channels;
bool m_fixedCenterFrequency; // Devices such as FileInput that can't have center freq changed
RRTurnPlan() = default; RRTurnPlan() = default;
RRTurnPlan(const RRTurnPlan&) = default; RRTurnPlan(const RRTurnPlan&) = default;
@ -157,10 +158,11 @@ private:
void removeVORChannel(int navId); void removeVORChannel(int navId);
void addVORChannel(const VORLocalizerSubChannelSettings& subChannelSettings); void addVORChannel(const VORLocalizerSubChannelSettings& subChannelSettings);
void updateChannels(); //!< (re)allocate channels to service VORs void updateChannels(); //!< (re)allocate channels to service VORs
void allocateChannel(ChannelAPI *channel, int vorFrequency, int vorNavId, int channelShift);
void setDeviceFrequency(int deviceIndex, double targetFrequency);
void setChannelShift(int deviceIndex, int channelIndex, double targetOffset, int vorNavId); void setChannelShift(int deviceIndex, int channelIndex, double targetOffset, int vorNavId);
void setAudioMute(int vorNavId, bool audioMute); void setAudioMute(int vorNavId, bool audioMute);
static quint64 getDeviceCenterFrequency(int deviceIndex);
static int getDeviceSampleRate(int deviceIndex);
static bool hasCenterFrequencySetting(int deviceIndex);
static void generateIndexCombinations(int length, int subLength, std::vector<std::vector<int>>& indexCombinations); static void generateIndexCombinations(int length, int subLength, std::vector<std::vector<int>>& indexCombinations);
static void getVORRanges(const QList<VORLocalizerSettings::VORChannel>& vors, int subLength, std::vector<VORRange>& vorRanges); static void getVORRanges(const QList<VORLocalizerSettings::VORChannel>& vors, int subLength, std::vector<VORRange>& vorRanges);
static void filterVORRanges(std::vector<VORRange>& vorRanges, int thresholdBW); static void filterVORRanges(std::vector<VORRange>& vorRanges, int thresholdBW);

View File

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