1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-23 10:05:46 -05:00

VOR single channel: first working release of VOR localizer feature plugin

This commit is contained in:
f4exb 2020-12-07 19:32:43 +01:00
parent ffe515fb63
commit 6c02a78d62
29 changed files with 1671 additions and 196 deletions

View File

@ -436,9 +436,17 @@ void VORDemodSC::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respon
response.getVorDemodScReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg));
response.getVorDemodScReport()->setSquelch(m_basebandSink->getSquelchOpen() ? 1 : 0);
response.getVorDemodScReport()->setAudioSampleRate(m_basebandSink->getAudioSampleRate());
response.getVorDemodScReport()->setNavId(m_settings.m_navId);
response.getVorDemodScReport()->setRadial(m_radial);
response.getVorDemodScReport()->setRefMag(m_refMag);
response.getVorDemodScReport()->setVarMag(m_varMag);
float refMagDB = std::round(20.0*std::log10(m_refMag));
float varMagDB = std::round(20.0*std::log10(m_varMag));
bool validRefMag = refMagDB > m_settings.m_refThresholdDB;
bool validVarMag = varMagDB > m_settings.m_varThresholdDB;
response.getVorDemodScReport()->setValidRadial(validRefMag && validVarMag ? 1 : 0);
response.getVorDemodScReport()->setValidRefMag(validRefMag ? 1 : 0);
response.getVorDemodScReport()->setValidVarMag(validVarMag ? 1 : 0);
if (response.getVorDemodScReport()->getMorseIdent()) {
*response.getVorDemodScReport()->getMorseIdent() = m_morseIdent;
@ -502,12 +510,15 @@ void VORDemodSC::featuresSendSettings(QList<QString>& channelSettingsKeys, const
void VORDemodSC::sendChannelReport(QList<MessageQueue*> *messageQueues)
{
SWGSDRangel::SWGChannelReport *swgChannelReport = new SWGSDRangel::SWGChannelReport();
webapiFormatChannelReport(*swgChannelReport);
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
SWGSDRangel::SWGChannelReport *swgChannelReport = new SWGSDRangel::SWGChannelReport();
swgChannelReport->setDirection(0);
swgChannelReport->setChannelType(new QString(m_channelId));
swgChannelReport->setVorDemodScReport(new SWGSDRangel::SWGVORDemodSCReport());
webapiFormatChannelReport(*swgChannelReport);
MainCore::MsgChannelReport *msg = MainCore::MsgChannelReport::create(this, swgChannelReport);
(*it)->push(msg);
}

View File

@ -303,6 +303,9 @@
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
@ -367,6 +370,9 @@
<property name="maximum">
<number>0</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>-40</number>
</property>
@ -416,6 +422,9 @@
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
</widget>
</item>
<item>
@ -655,7 +664,6 @@
</tabstops>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="map.qrc"/>
<include location="icons.qrc"/>
</resources>
<connections/>

View File

@ -302,7 +302,7 @@ void VORDemodSCSink::processOneSample(Complex &ci)
{
if (m_ident != "")
{
qDebug() << m_ident << " " << Morse::toString(m_ident);
qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident);
if (getMessageQueueToChannel())
{
@ -343,7 +343,7 @@ void VORDemodSCSink::processOneSample(Complex &ci)
m_ident = m_ident.simplified();
if (m_ident != "")
{
qDebug() << m_ident << " " << Morse::toString(m_ident);
qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident);
if (getMessageQueueToChannel())
{

View File

@ -25,9 +25,16 @@
#include "SWGFeatureActions.h"
#include "SWGSimplePTTReport.h"
#include "SWGDeviceState.h"
#include "SWGChannelReport.h"
#include "dsp/dspengine.h"
#include "dsp/dspdevicesourceengine.h"
#include "dsp/devicesamplesource.h"
#include "device/deviceset.h"
#include "channel/channelapi.h"
#include "maincore.h"
#include "vorlocalizerreport.h"
#include "vorlocalizerworker.h"
#include "vorlocalizer.h"
@ -41,8 +48,7 @@ const char* const VORLocalizer::m_featureIdURI = "sdrangel.feature.vorlocalizer"
const char* const VORLocalizer::m_featureId = "VORLocalizer";
VORLocalizer::VORLocalizer(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface),
m_ptt(false)
Feature(m_featureIdURI, webAPIAdapterInterface)
{
setObjectName(m_featureId);
m_worker = new VorLocalizerWorker(webAPIAdapterInterface);
@ -64,7 +70,8 @@ void VORLocalizer::start()
qDebug("VORLocalizer::start");
m_worker->reset();
m_worker->setMessageQueueToGUI(getMessageQueueToGUI());
m_worker->setMessageQueueToFeature(getInputMessageQueue());
m_worker->setAvailableChannels(&m_availableChannels);
bool ok = m_worker->startWork();
m_state = ok ? StRunning : StError;
m_thread.start();
@ -108,11 +115,129 @@ bool VORLocalizer::handleMessage(const Message& cmd)
else if (MsgRefreshChannels::match(cmd))
{
qDebug() << "VORLocalizer::handleMessage: MsgRefreshChannels";
VorLocalizerWorker::MsgRefreshChannels *msg = VorLocalizerWorker::MsgRefreshChannels::create();
m_worker->getInputMessageQueue()->push(msg);
updateChannels();
return true;
}
else
else if (MainCore::MsgChannelReport::match(cmd))
{
MainCore::MsgChannelReport& report = (MainCore::MsgChannelReport&) cmd;
SWGSDRangel::SWGChannelReport* swgChannelReport = report.getSWGReport();
QString *channelType = swgChannelReport->getChannelType();
if (*channelType == "VORDemodSC")
{
SWGSDRangel::SWGVORDemodSCReport *swgVORDemodSCReport = swgChannelReport->getVorDemodScReport();
int navId = swgVORDemodSCReport->getNavId();
if (navId < 0) { // disregard message for unallocated channels
return true;
}
bool singlePlan = (m_vorSinglePlans.contains(navId)) ? m_vorSinglePlans[navId] : false;
// qDebug() << "VORLocalizer::handleMessage: MainCore::MsgChannelReport(VORDemodSC): "
// << "navId:" << navId
// << "singlePlanProvided" << m_vorSinglePlans.contains(navId)
// << "singlePlan:" << singlePlan;
if (m_vorChannelReports.contains(navId))
{
m_vorChannelReports[navId].m_radial = swgVORDemodSCReport->getRadial();
m_vorChannelReports[navId].m_refMag = swgVORDemodSCReport->getRefMag();
m_vorChannelReports[navId].m_varMag = swgVORDemodSCReport->getVarMag();
m_vorChannelReports[navId].m_validRadial = swgVORDemodSCReport->getValidRadial() != 0;
m_vorChannelReports[navId].m_validRefMag = swgVORDemodSCReport->getValidRefMag() != 0;
m_vorChannelReports[navId].m_validVarMag = swgVORDemodSCReport->getValidVarMag() != 0;
m_vorChannelReports[navId].m_morseIdent = *swgVORDemodSCReport->getMorseIdent();
}
else
{
m_vorChannelReports[navId] = VORChannelReport{
swgVORDemodSCReport->getRadial(),
swgVORDemodSCReport->getRefMag(),
swgVORDemodSCReport->getVarMag(),
AverageUtil<float, double>(),
AverageUtil<float, double>(),
AverageUtil<float, double>(),
swgVORDemodSCReport->getValidRadial() != 0,
swgVORDemodSCReport->getValidRefMag() != 0,
swgVORDemodSCReport->getValidVarMag() != 0,
*swgVORDemodSCReport->getMorseIdent()
};
}
if (m_vorChannelReports[navId].m_validRadial) {
m_vorChannelReports[navId].m_radialAvg(swgVORDemodSCReport->getRadial());
}
if (m_vorChannelReports[navId].m_validRefMag) {
m_vorChannelReports[navId].m_refMagAvg(swgVORDemodSCReport->getRefMag());
}
if (m_vorChannelReports[navId].m_validVarMag) {
m_vorChannelReports[navId].m_varMagAvg(swgVORDemodSCReport->getVarMag());
}
if (getMessageQueueToGUI())
{
float radial = ((m_vorChannelReports[navId].m_radialAvg.getNumSamples() == 0) || singlePlan) ?
m_vorChannelReports[navId].m_radial :
m_vorChannelReports[navId].m_radialAvg.instantAverage();
float refMag = ((m_vorChannelReports[navId].m_refMagAvg.getNumSamples() == 0) || singlePlan) ?
m_vorChannelReports[navId].m_refMag :
m_vorChannelReports[navId].m_refMagAvg.instantAverage();
float varMag = ((m_vorChannelReports[navId].m_varMagAvg.getNumSamples() == 0) || singlePlan) ?
m_vorChannelReports[navId].m_varMag :
m_vorChannelReports[navId].m_varMagAvg.instantAverage();
bool validRadial = singlePlan ? m_vorChannelReports[navId].m_validRadial :
m_vorChannelReports[navId].m_radialAvg.getNumSamples() != 0 || m_vorChannelReports[navId].m_validRadial;
bool validRefMag = singlePlan ? m_vorChannelReports[navId].m_validRefMag :
m_vorChannelReports[navId].m_refMagAvg.getNumSamples() != 0 || m_vorChannelReports[navId].m_validRefMag;
bool validVarMag = singlePlan ? m_vorChannelReports[navId].m_validVarMag :
m_vorChannelReports[navId].m_varMagAvg.getNumSamples() != 0 || m_vorChannelReports[navId].m_validVarMag;
VORLocalizerReport::MsgReportRadial *msgRadial = VORLocalizerReport::MsgReportRadial::create(
navId,
radial,
refMag,
varMag,
validRadial,
validRefMag,
validVarMag
);
getMessageQueueToGUI()->push(msgRadial);
VORLocalizerReport::MsgReportIdent *msgIdent = VORLocalizerReport::MsgReportIdent::create(
navId,
m_vorChannelReports[navId].m_morseIdent
);
getMessageQueueToGUI()->push(msgIdent);
}
}
return true;
}
else if (VORLocalizerReport::MsgReportServiceddVORs::match(cmd))
{
qDebug() << "VORLocalizer::handleMessage: MsgReportServiceddVORs:";
VORLocalizerReport::MsgReportServiceddVORs& report = (VORLocalizerReport::MsgReportServiceddVORs&) cmd;
std::vector<int>& vorNavIds = report.getNavIds();
m_vorSinglePlans = report.getSinglePlans();
for (std::vector<int>::const_iterator it = vorNavIds.begin(); it != vorNavIds.end(); ++it)
{
m_vorChannelReports[*it].m_radialAvg.reset();
m_vorChannelReports[*it].m_refMagAvg.reset();
m_vorChannelReports[*it].m_varMagAvg.reset();
}
if (getMessageQueueToGUI())
{
VORLocalizerReport::MsgReportServiceddVORs *msgToGUI = VORLocalizerReport::MsgReportServiceddVORs::create();
msgToGUI->getNavIds() = vorNavIds;
getMessageQueueToGUI()->push(msgToGUI);
}
return true;
}
else
{
return false;
}
@ -146,6 +271,8 @@ void VORLocalizer::applySettings(const VORLocalizerSettings& settings, bool forc
<< " m_title: " << settings.m_title
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_magDecAdjust: " << settings.m_magDecAdjust
<< " m_rrTime: " << settings.m_rrTime
<< " m_centerShift: " << settings.m_centerShift
<< " force: " << force;
QList<QString> reverseAPIKeys;
@ -159,6 +286,12 @@ void VORLocalizer::applySettings(const VORLocalizerSettings& settings, bool forc
if ((m_settings.m_magDecAdjust != settings.m_magDecAdjust) || force) {
reverseAPIKeys.append("magDecAdjust");
}
if ((m_settings.m_rrTime != settings.m_rrTime) || force) {
reverseAPIKeys.append("rrTime");
}
if ((m_settings.m_centerShift != settings.m_centerShift) || force) {
reverseAPIKeys.append("centerShift");
}
VorLocalizerWorker::MsgConfigureVORLocalizerWorker *msg = VorLocalizerWorker::MsgConfigureVORLocalizerWorker::create(
settings, force
@ -178,6 +311,75 @@ void VORLocalizer::applySettings(const VORLocalizerSettings& settings, bool forc
m_settings = settings;
}
void VORLocalizer::updateChannels()
{
MainCore *mainCore = MainCore::instance();
MessagePipes& messagePipes = mainCore->getMessagePipes();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
std::vector<DeviceSet*>::const_iterator it = deviceSets.begin();
m_availableChannels.clear();
int deviceIndex = 0;
for (; it != deviceSets.end(); ++it, deviceIndex++)
{
DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
if (deviceSourceEngine)
{
DeviceSampleSource *deviceSource = deviceSourceEngine->getSource();
quint64 deviceCenterFrequency = deviceSource->getCenterFrequency();
int basebandSampleRate = deviceSource->getSampleRate();
for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++)
{
ChannelAPI *channel = (*it)->getChannelAt(chi);
if (channel->getURI() == "sdrangel.channel.vordemodsc")
{
if (!m_availableChannels.contains(channel))
{
MessageQueue *messageQueue = messagePipes.registerChannelToFeature(channel, this, "report");
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleChannelMessageQueue(messageQueue); },
Qt::QueuedConnection
);
}
VORLocalizerSettings::AvailableChannel availableChannel =
VORLocalizerSettings::AvailableChannel{deviceIndex, chi, channel, deviceCenterFrequency, basebandSampleRate, -1};
m_availableChannels[channel] = availableChannel;
}
}
}
}
if (getMessageQueueToGUI())
{
VORLocalizerReport::MsgReportChannels *msgToGUI = VORLocalizerReport::MsgReportChannels::create();
std::vector<VORLocalizerReport::MsgReportChannels::Channel>& msgChannels = msgToGUI->getChannels();
QHash<ChannelAPI*, VORLocalizerSettings::AvailableChannel>::iterator it = m_availableChannels.begin();
for (; it != m_availableChannels.end(); ++it)
{
VORLocalizerReport::MsgReportChannels::Channel msgChannel =
VORLocalizerReport::MsgReportChannels::Channel{
it->m_deviceSetIndex,
it->m_channelIndex
};
msgChannels.push_back(msgChannel);
}
getMessageQueueToGUI()->push(msgToGUI);
}
VorLocalizerWorker::MsgRefreshChannels *msgToWorker = VorLocalizerWorker::MsgRefreshChannels::create();
m_worker->getInputMessageQueue()->push(msgToWorker);
}
int VORLocalizer::webapiRun(bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
@ -237,6 +439,8 @@ void VORLocalizer::webapiFormatFeatureSettings(
response.getVorLocalizerSettings()->setRgbColor(settings.m_rgbColor);
response.getVorLocalizerSettings()->setMagDecAdjust(settings.m_magDecAdjust);
response.getVorLocalizerSettings()->setRrTime(settings.m_rrTime);
response.getVorLocalizerSettings()->setCenterShift(settings.m_centerShift);
response.getVorLocalizerSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
@ -265,6 +469,12 @@ void VORLocalizer::webapiUpdateFeatureSettings(
if (featureSettingsKeys.contains("magDecAdjust")) {
settings.m_magDecAdjust = response.getVorLocalizerSettings()->getMagDecAdjust();
}
if (featureSettingsKeys.contains("rrTime")) {
settings.m_rrTime = response.getVorLocalizerSettings()->getRrTime();
}
if (featureSettingsKeys.contains("centerShift")) {
settings.m_centerShift = response.getVorLocalizerSettings()->getCenterShift();
}
if (featureSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getVorLocalizerSettings()->getUseReverseApi() != 0;
}
@ -302,6 +512,12 @@ void VORLocalizer::webapiReverseSendSettings(QList<QString>& channelSettingsKeys
if (channelSettingsKeys.contains("magDecAdjust") || force) {
swgVORLocalizerSettings->setMagDecAdjust(settings.m_magDecAdjust);
}
if (channelSettingsKeys.contains("rrTime") || force) {
swgVORLocalizerSettings->setRrTime(settings.m_rrTime);
}
if (channelSettingsKeys.contains("centerShift") || force) {
swgVORLocalizerSettings->setCenterShift(settings.m_centerShift);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings")
.arg(settings.m_reverseAPIAddress)
@ -343,3 +559,15 @@ void VORLocalizer::networkManagerFinished(QNetworkReply *reply)
reply->deleteLater();
}
void VORLocalizer::handleChannelMessageQueue(MessageQueue* messageQueue)
{
Message* message;
while ((message = messageQueue->pop()) != nullptr)
{
if (handleMessage(*message)) {
delete message;
}
}
}

View File

@ -23,6 +23,7 @@
#include "feature/feature.h"
#include "util/message.h"
#include "util/average.h"
#include "vorlocalizersettings.h"
@ -170,10 +171,30 @@ public:
static const char* const m_featureId;
private:
struct VORChannelReport
{
float m_radial; //!< current detected radial
float m_refMag; //!< current reference signal magnitude
float m_varMag; //!< current variable signal magnitude
AverageUtil<float, double> m_radialAvg;
AverageUtil<float, double> m_refMagAvg;
AverageUtil<float, double> m_varMagAvg;
bool m_validRadial;
bool m_validRefMag;
bool m_validVarMag;
QString m_morseIdent; //!< identification morse code transcript
VORChannelReport() = default;
VORChannelReport(const VORChannelReport&) = default;
VORChannelReport& operator=(const VORChannelReport&) = default;
};
QThread m_thread;
VorLocalizerWorker *m_worker;
VORLocalizerSettings m_settings;
bool m_ptt;
QHash<ChannelAPI*, VORLocalizerSettings::AvailableChannel> m_availableChannels;
QHash<int, VORChannelReport> m_vorChannelReports;
QHash<int, bool> m_vorSinglePlans;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
@ -181,10 +202,13 @@ private:
void start();
void stop();
void applySettings(const VORLocalizerSettings& settings, bool force = false);
void updateChannels();
void webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const VORLocalizerSettings& settings, bool force);
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleChannelMessageQueue(MessageQueue* messageQueue);
};
#endif // INCLUDE_FEATURE_VORLOCALIZER_H_

View File

@ -333,8 +333,10 @@ static bool calcIntersectionPoint(float lat1, float lon1, float bearing1, float
double cosLat1 = cos(lat1Rad);
double cosLat2 = cos(lat2Rad);
double delta12 = 2.0 * asin(sqrt(sindlat*sindlat+cosLat1*cosLat2*sindlon*sindlon));
if (abs(delta12) < std::numeric_limits<float>::epsilon())
if (abs(delta12) < std::numeric_limits<float>::epsilon()) {
return false;
}
double sinLat1 = sin(lat1Rad);
double sinLat2 = sin(lat2Rad);
@ -342,8 +344,8 @@ static bool calcIntersectionPoint(float lat1, float lon1, float bearing1, float
double cosDelta12 = cos(delta12);
double thetaA = acos((sinLat2-sinLat1*cosDelta12)/(sinDelta12*cosLat1));
double thetaB = acos((sinLat1-sinLat2*cosDelta12)/(sinDelta12*cosLat2));
double theta12, theta21;
if (sin(lon2Rad-lon1Rad) > 0.0)
{
theta12 = thetaA;
@ -354,14 +356,19 @@ static bool calcIntersectionPoint(float lat1, float lon1, float bearing1, float
theta12 = 2.0*M_PI-thetaA;
theta21 = thetaB;
}
double alpha1 = theta13 - theta12;
double alpha2 = theta21 - theta23;
double sinAlpha1 = sin(alpha1);
double sinAlpha2 = sin(alpha2);
if ((sinAlpha1 == 0.0) && (sinAlpha2 == 0.0))
if ((sinAlpha1 == 0.0) && (sinAlpha2 == 0.0)) {
return false;
if (sinAlpha1*sinAlpha2 < 0.0)
}
if (sinAlpha1*sinAlpha2 < 0.0) {
return false;
}
double cosAlpha1 = cos(alpha1);
double cosAlpha2 = cos(alpha2);
double cosAlpha3 = -cosAlpha1*cosAlpha2+sinAlpha1*sinAlpha2*cos(delta12);
@ -382,7 +389,7 @@ VORGUI::VORGUI(NavAid *navAid, VORLocalizerGUI *gui) :
// These are deleted by QTableWidget
m_nameItem = new QTableWidgetItem();
m_frequencyItem = new QTableWidgetItem();
m_offsetItem = new QTableWidgetItem();
m_navIdItem = new QTableWidgetItem();
m_radialItem = new QTableWidgetItem();
m_identItem = new QTableWidgetItem();
m_morseItem = new QTableWidgetItem();
@ -412,15 +419,18 @@ VORGUI::VORGUI(NavAid *navAid, VORLocalizerGUI *gui) :
void VORGUI::on_audioMute_toggled(bool checked)
{
m_gui->m_settings.m_subChannelSettings.value(m_navAid->m_id)->m_audioMute = checked;
m_gui->m_settings.m_subChannelSettings[m_navAid->m_id].m_audioMute = checked;
m_gui->applySettings();
}
QVariant VORModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
if ((row < 0) || (row >= m_vors.count()))
if ((row < 0) || (row >= m_vors.count())) {
return QVariant();
}
if (role == VORModel::positionRole)
{
// Coordinates to display the VOR icon at
@ -436,15 +446,22 @@ QVariant VORModel::data(const QModelIndex &index, int role) const
QStringList list;
list.append(QString("Name: %1").arg(m_vors[row]->m_name));
list.append(QString("Frequency: %1 MHz").arg(m_vors[row]->m_frequencykHz / 1000.0f, 0, 'f', 1));
if (m_vors[row]->m_channel != "")
if (m_vors[row]->m_channel != "") {
list.append(QString("Channel: %1").arg(m_vors[row]->m_channel));
}
list.append(QString("Ident: %1 %2").arg(m_vors[row]->m_ident).arg(Morse::toSpacedUnicodeMorse(m_vors[row]->m_ident)));
list.append(QString("Range: %1 nm").arg(m_vors[row]->m_range));
if (m_vors[row]->m_alignedTrueNorth)
if (m_vors[row]->m_alignedTrueNorth) {
list.append(QString("Magnetic declination: Aligned to true North"));
else if (m_vors[row]->m_magneticDeclination != 0.0f)
} else if (m_vors[row]->m_magneticDeclination != 0.0f) {
list.append(QString("Magnetic declination: %1%2").arg(std::round(m_vors[row]->m_magneticDeclination)).arg(QChar(0x00b0)));
}
QString data = list.join("\n");
return QVariant::fromValue(data);
}
else if (role == VORModel::vorImageRole)
@ -455,10 +472,11 @@ QVariant VORModel::data(const QModelIndex &index, int role) const
else if (role == VORModel::bubbleColourRole)
{
// Select a background colour for the text bubble next to the VOR
if (m_selected[row])
if (m_selected[row]) {
return QVariant::fromValue(QColor("lightgreen"));
else
} else {
return QVariant::fromValue(QColor("lightblue"));
}
}
else if (role == VORModel::vorRadialRole)
{
@ -471,10 +489,13 @@ QVariant VORModel::data(const QModelIndex &index, int role) const
float endLat, endLong;
float bearing;
if (m_gui->m_settings.m_magDecAdjust && !m_vors[row]->m_alignedTrueNorth)
if (m_gui->m_settings.m_magDecAdjust && !m_vors[row]->m_alignedTrueNorth) {
bearing = m_radials[row] - m_vors[row]->m_magneticDeclination;
else
} else {
bearing = m_radials[row];
}
calcRadialEndPoint(m_vors[row]->m_latitude, m_vors[row]->m_longitude, m_vors[row]->getRangeMetres(), bearing, endLat, endLong);
list.push_back(QVariant::fromValue(*new QGeoCoordinate(endLat, endLong, Units::feetToMetres(m_vors[row]->m_elevation))));
@ -484,36 +505,49 @@ QVariant VORModel::data(const QModelIndex &index, int role) const
return QVariantList();
}
else if (role == VORModel::selectedRole)
{
return QVariant::fromValue(m_selected[row]);
}
return QVariant();
}
bool VORModel::setData(const QModelIndex &index, const QVariant& value, int role)
{
int row = index.row();
if ((row < 0) || (row >= m_vors.count()))
if ((row < 0) || (row >= m_vors.count())) {
return false;
}
if (role == VORModel::selectedRole)
{
bool selected = value.toBool();
VORGUI *vorGUI;
if (selected == true)
if (selected)
{
vorGUI = new VORGUI(m_vors[row], m_gui);
m_vorGUIs[row] = vorGUI;
}
else
{
vorGUI = m_vorGUIs[row];
}
m_gui->selectVOR(vorGUI, selected);
m_selected[row] = selected;
emit dataChanged(index, index);
if (!selected)
{
delete vorGUI;
m_vorGUIs[row] = nullptr;
}
return true;
}
return true;
}
@ -533,28 +567,33 @@ bool VORModel::findIntersection(float &lat, float &lon)
{
lat1 = m_vors[i]->m_latitude;
lon1 = m_vors[i]->m_longitude;
if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth)
if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth) {
bearing1 = m_radials[i] - m_vors[i]->m_magneticDeclination;
else
} else {
bearing1 = m_radials[i];
}
valid1 = true;
}
else
{
lat2 = m_vors[i]->m_latitude;
lon2 = m_vors[i]->m_longitude;
if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth)
if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth) {
bearing2 = m_radials[i] - m_vors[i]->m_magneticDeclination;
else
} else {
bearing2 = m_radials[i];
}
valid2 = true;
break;
}
}
}
if (valid1 && valid2)
{
if (valid1 && valid2) {
return calcIntersectionPoint(lat1, lon1, bearing1, lat2, lon2, bearing2, lat, lon);
}
}
@ -571,7 +610,7 @@ void VORLocalizerGUI::resizeTable()
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_FREQUENCY, new QTableWidgetItem("Freq (MHz) "));
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_OFFSET, new QTableWidgetItem("Offset (kHz) "));
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_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse)));
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, new QTableWidgetItem("Radial (o) "));
@ -588,7 +627,6 @@ void VORLocalizerGUI::resizeTable()
void VORLocalizerGUI::vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
{
(void) oldVisualIndex;
m_settings.m_columnIndexes[logicalIndex] = newVisualIndex;
}
@ -596,7 +634,6 @@ void VORLocalizerGUI::vorData_sectionMoved(int logicalIndex, int oldVisualIndex,
void VORLocalizerGUI::vorData_sectionResized(int logicalIndex, int oldSize, int newSize)
{
(void) oldSize;
m_settings.m_columnSizes[logicalIndex] = newSize;
}
@ -610,9 +647,9 @@ void VORLocalizerGUI::columnSelectMenu(QPoint pos)
void VORLocalizerGUI::columnSelectMenuChecked(bool checked)
{
(void) checked;
QAction* action = qobject_cast<QAction*>(sender());
if (action != nullptr)
if (action)
{
int idx = action->data().toInt(nullptr);
ui->vorData->setColumnHidden(idx, !action->isChecked());
@ -627,6 +664,7 @@ QAction *VORLocalizerGUI::createCheckableItem(QString &text, int idx, bool check
action->setChecked(checked);
action->setData(QVariant(idx));
connect(action, SIGNAL(triggered()), this, SLOT(columnSelectMenuChecked()));
return action;
}
@ -646,7 +684,7 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
ui->vorData->setRowCount(row + 1);
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_OFFSET, vorGUI->m_offsetItem);
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_MORSE, vorGUI->m_morseItem);
ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, vorGUI->m_radialItem);
@ -662,11 +700,11 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
ui->vorData->setSortingEnabled(true);
// Add to settings to create corresponding demodulator
VORLocalizerSubChannelSettings *subChannelSettings = new VORLocalizerSubChannelSettings();
subChannelSettings->m_id = navId;
subChannelSettings->m_frequency = vorGUI->m_navAid->m_frequencykHz * 1000;
subChannelSettings->m_audioMute = false;
m_settings.m_subChannelSettings.insert(navId, subChannelSettings);
m_settings.m_subChannelSettings.insert(navId, VORLocalizerSubChannelSettings{
navId,
vorGUI->m_navAid->m_frequencykHz * 1000,
false
});
applySettings();
}
@ -678,9 +716,7 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected)
m_selectedVORs.remove(navId);
ui->vorData->removeRow(vorGUI->m_nameItem->row());
// Remove from settings to remove corresponding demodulator
VORLocalizerSubChannelSettings *subChannelSettings = m_settings.m_subChannelSettings.value(navId);
m_settings.m_subChannelSettings.remove(navId);
delete subChannelSettings;
applySettings();
}
@ -701,10 +737,10 @@ void VORLocalizerGUI::updateVORs()
azEl.calculate();
// Only display VOR if in range
if (azEl.getDistance() <= 200000)
{
if (azEl.getDistance() <= 200000) {
m_vorModel.addVOR(vor);
}
++i;
}
}
@ -734,11 +770,14 @@ QByteArray VORLocalizerGUI::serialize() const
bool VORLocalizerGUI::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
if (m_settings.deserialize(data))
{
displaySettings();
applySettings(true);
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
@ -775,50 +814,36 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
Real refMagDB = std::round(20.0*std::log10(report.getRefMag()));
bool validRadial = report.getValidRadial();
vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial()));
if (validRadial)
vorGUI->m_navIdItem->setData(Qt::DisplayRole, subChannelId);
if (validRadial) {
vorGUI->m_radialItem->setForeground(QBrush(Qt::white));
else
} else {
vorGUI->m_radialItem->setForeground(QBrush(Qt::red));
}
vorGUI->m_refMagItem->setData(Qt::DisplayRole, refMagDB);
if (report.getValidRefMag())
if (report.getValidRefMag()) {
vorGUI->m_refMagItem->setForeground(QBrush(Qt::white));
else
} else {
vorGUI->m_refMagItem->setForeground(QBrush(Qt::red));
}
vorGUI->m_varMagItem->setData(Qt::DisplayRole, varMagDB);
if (report.getValidVarMag())
if (report.getValidVarMag()) {
vorGUI->m_varMagItem->setForeground(QBrush(Qt::white));
else
} else {
vorGUI->m_varMagItem->setForeground(QBrush(Qt::red));
}
// Update radial on map
m_vorModel.setRadial(subChannelId, validRadial, report.getRadial());
return true;
}
else if (VORLocalizerReport::MsgReportFreqOffset::match(message))
{
VORLocalizerReport::MsgReportFreqOffset& report = (VORLocalizerReport::MsgReportFreqOffset&) message;
int subChannelId = report.getSubChannelId();
VORGUI *vorGUI = m_selectedVORs.value(subChannelId);
vorGUI->m_offsetItem->setData(Qt::DisplayRole, report.getFreqOffset() / 1000.0);
if (report.getOutOfBand())
{
vorGUI->m_offsetItem->setForeground(QBrush(Qt::red));
// Clear other fields as data is now invalid
vorGUI->m_radialItem->setText("");
vorGUI->m_refMagItem->setText("");
vorGUI->m_varMagItem->setText("");
m_vorModel.setRadial(subChannelId, false, -1.0f);
}
else
vorGUI->m_offsetItem->setForeground(QBrush(Qt::white));
}
else if (VORLocalizerReport::MsgReportIdent::match(message))
{
VORLocalizerReport::MsgReportIdent& report = (VORLocalizerReport::MsgReportIdent&) message;
@ -835,6 +860,7 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
{
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
@ -868,11 +894,29 @@ bool VORLocalizerGUI::handleMessage(const Message& message)
ui->channels->clear();
for (; it != channels.end(); ++it) {
ui->channels->addItem(tr("%1:%2").arg(it->m_deviceSetIndex).arg(it->m_channelIndex));
ui->channels->addItem(tr("R%1:%2").arg(it->m_deviceSetIndex).arg(it->m_channelIndex));
}
return true;
}
else if (VORLocalizerReport::MsgReportServiceddVORs::match(message))
{
VORLocalizerReport::MsgReportServiceddVORs& report = (VORLocalizerReport::MsgReportServiceddVORs&) message;
std::vector<int>& servicedVORNavIds = report.getNavIds();
for (auto vorGUI : m_selectedVORs) {
vorGUI->m_frequencyItem->setForeground(QBrush(Qt::white));
}
for (auto navId : servicedVORNavIds)
{
if (m_selectedVORs.contains(navId))
{
VORGUI *vorGUI = m_selectedVORs[navId];
vorGUI->m_frequencyItem->setForeground(QBrush(Qt::green));
}
}
}
return false;
}
@ -883,8 +927,7 @@ void VORLocalizerGUI::handleInputMessages()
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
if (handleMessage(*message)) {
delete message;
}
}
@ -893,31 +936,41 @@ void VORLocalizerGUI::handleInputMessages()
qint64 VORLocalizerGUI::fileAgeInDays(QString filename)
{
QFile file(filename);
if (file.exists())
{
QDateTime modified = file.fileTime(QFileDevice::FileModificationTime);
if (modified.isValid())
if (modified.isValid()) {
return modified.daysTo(QDateTime::currentDateTime());
else
} 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)
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)
} 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
} 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;
}
}
@ -932,18 +985,20 @@ QString VORLocalizerGUI::getDataDir()
QString VORLocalizerGUI::getOpenAIPVORDBFilename(int i)
{
if (countryCodes[i] != nullptr)
if (countryCodes[i] != nullptr) {
return getDataDir() + "/" + countryCodes[i] + "_nav.aip";
else
} else {
return "";
}
}
QString VORLocalizerGUI::getOpenAIPVORDBURL(int i)
{
if (countryCodes[i] != nullptr)
if (countryCodes[i] != nullptr) {
return QString(OPENAIP_NAVAIDS_URL).arg(countryCodes[i]);
else
} else {
return "";
}
}
QString VORLocalizerGUI::getVORDBFilename()
@ -964,14 +1019,18 @@ void VORLocalizerGUI::downloadFinished(const QString& filename, bool success)
if (filename == getVORDBFilename())
{
m_vors = NavAid::readNavAidsDB(filename);
if (m_vors != nullptr)
if (m_vors != nullptr) {
updateVORs();
}
m_progressDialog->close();
m_progressDialog = nullptr;
}
else if (filename == getOpenAIPVORDBFilename(m_countryIndex))
{
m_countryIndex++;
if (countryCodes[m_countryIndex] != nullptr)
{
QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex);
@ -984,8 +1043,11 @@ void VORLocalizerGUI::downloadFinished(const QString& filename, bool success)
else
{
readNavAids();
if (m_vors != nullptr)
if (m_vors) {
updateVORs();
}
m_progressDialog->close();
m_progressDialog = nullptr;
}
@ -1021,6 +1083,7 @@ void VORLocalizerGUI::on_getOurAirportsVORDB_clicked()
if (m_progressDialog == nullptr)
{
QString vorDBFile = getVORDBFilename();
if (confirmDownload(vorDBFile))
{
// Download OurAirports navaid database to disk
@ -1039,10 +1102,11 @@ void VORLocalizerGUI::on_getOurAirportsVORDB_clicked()
void VORLocalizerGUI::on_getOpenAIPVORDB_clicked()
{
// Don't try to download while already in progress
if (m_progressDialog == nullptr)
if (!m_progressDialog)
{
m_countryIndex = 0;
QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex);
if (confirmDownload(vorDBFile))
{
// Download OpenAIP XML to disk
@ -1071,13 +1135,27 @@ void VORLocalizerGUI::readNavAids()
}
}
void VORLocalizerGUI::on_magDecAdjust_clicked(bool checked)
void VORLocalizerGUI::on_magDecAdjust_toggled(bool checked)
{
m_settings.m_magDecAdjust = checked;
m_vorModel.allVORUpdated();
applySettings();
}
void VORLocalizerGUI::on_rrTime_valueChanged(int value)
{
m_settings.m_rrTime = value;
ui->rrTimeText->setText(tr("%1s").arg(m_settings.m_rrTime));
applySettings();
}
void VORLocalizerGUI::on_centerShift_valueChanged(int value)
{
m_settings.m_centerShift = value * 1000;
ui->centerShiftText->setText(tr("%1k").arg(value));
applySettings();
}
void VORLocalizerGUI::on_channelsRefresh_clicked()
{
if (m_doApplySettings)
@ -1170,6 +1248,7 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
// Centre map at My Position
QQuickItem *item = ui->map->rootObject();
QObject *object = item->findChild<QObject*>("map");
if (object)
{
QGeoCoordinate coords = object->property("center").value<QGeoCoordinate>();
@ -1177,8 +1256,10 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
coords.setLongitude(stationLongitude);
object->setProperty("center", QVariant::fromValue(coords));
}
// Move antenna icon to My Position to start with
QObject *stationObject = item->findChild<QObject*>("station");
if (stationObject)
{
QGeoCoordinate coords = stationObject->property("coordinate").value<QGeoCoordinate>();
@ -1191,6 +1272,7 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
// Read in VOR information if it exists
bool useOurAirports = false;
if (useOurAirports)
{
m_vors = NavAid::readNavAidsDB(getVORDBFilename());
@ -1201,7 +1283,8 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
readNavAids();
ui->getOurAirportsVORDB->setVisible(false);
}
if (m_vors != nullptr) {
if (m_vors) {
updateVORs();
}
@ -1213,11 +1296,13 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe
ui->vorData->setSortingEnabled(true);
// Add context menu to allow hiding/showing of columns
menu = new QMenu(ui->vorData);
for (int i = 0; i < ui->vorData->horizontalHeader()->count(); i++)
{
QString text = ui->vorData->horizontalHeaderItem(i)->text();
menu->addAction(createCheckableItem(text, i, true));
}
ui->vorData->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->vorData->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(columnSelectMenu(QPoint)));
// Get signals when columns change
@ -1273,6 +1358,11 @@ void VORLocalizerGUI::displaySettings()
header->moveSection(header->visualIndex(i), m_settings.m_columnIndexes[i]);
}
ui->rrTimeText->setText(tr("%1s").arg(m_settings.m_rrTime));
ui->rrTime->setValue(m_settings.m_rrTime);
ui->centerShiftText->setText(tr("%1k").arg(m_settings.m_centerShift/1000));
ui->centerShift->setValue(m_settings.m_centerShift/1000);
blockApplySettings(false);
}
@ -1325,6 +1415,7 @@ void VORLocalizerGUI::tick()
// Move antenna icon to estimated position
QQuickItem *item = ui->map->rootObject();
QObject *stationObject = item->findChild<QObject*>("station");
if(stationObject != NULL)
{
QGeoCoordinate coords = stationObject->property("coordinate").value<QGeoCoordinate>();

View File

@ -62,7 +62,7 @@ public:
QTableWidgetItem *m_nameItem;
QTableWidgetItem *m_frequencyItem;
QTableWidgetItem *m_offsetItem;
QTableWidgetItem *m_navIdItem;
QTableWidgetItem *m_identItem;
QTableWidgetItem *m_morseItem;
QTableWidgetItem *m_radialItem;
@ -269,7 +269,9 @@ private slots:
void on_startStop_toggled(bool checked);
void on_getOurAirportsVORDB_clicked();
void on_getOpenAIPVORDB_clicked();
void on_magDecAdjust_clicked(bool checked);
void on_magDecAdjust_toggled(bool checked);
void on_rrTime_valueChanged(int value);
void on_centerShift_valueChanged(int value);
void on_channelsRefresh_clicked();
void vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
void vorData_sectionResized(int logicalIndex, int oldSize, int newSize);

View File

@ -120,7 +120,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="magDecAdjust">
<widget class="ButtonSwitch" name="magDecAdjust">
<property name="toolTip">
<string>Draw radials adjusted for magnetic declination</string>
</property>
@ -139,6 +139,124 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rrTimeLabel">
<property name="text">
<string>RR</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="rrTime">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Round robin turn time (s)</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>60</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="pageStep">
<number>5</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rrTimeText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Sound volume (%)</string>
</property>
<property name="text">
<string>20s</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="centerShiftLabel">
<property name="text">
<string>Sh</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="centerShift">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Center frequency shift (kHz)</string>
</property>
<property name="minimum">
<number>-40</number>
</property>
<property name="maximum">
<number>40</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="centerShiftText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>20k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
@ -159,7 +277,7 @@
<item>
<widget class="QLabel" name="channelsLabel">
<property name="text">
<string>VORs</string>
<string>Chan</string>
</property>
</widget>
</item>
@ -264,7 +382,7 @@
</column>
<column>
<property name="text">
<string>Offset (kHz)</string>
<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>

View File

@ -17,7 +17,7 @@
#include "vorlocalizerreport.h"
MESSAGE_CLASS_DEFINITION(VORLocalizerReport::MsgReportFreqOffset, Message)
MESSAGE_CLASS_DEFINITION(VORLocalizerReport::MsgReportRadial, Message)
MESSAGE_CLASS_DEFINITION(VORLocalizerReport::MsgReportIdent, Message)
MESSAGE_CLASS_DEFINITION(VORLocalizerReport::MsgReportChannels, Message)
MESSAGE_CLASS_DEFINITION(VORLocalizerReport::MsgReportServiceddVORs, Message)

View File

@ -20,6 +20,7 @@
#define INCLUDE_VORLOCALIZERREPORT_H
#include <QObject>
#include <QHash>
#include "util/message.h"
@ -90,33 +91,6 @@ public:
}
};
class MsgReportFreqOffset : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSubChannelId() const { return m_subChannelId; }
int getFreqOffset() const { return m_freqOffset; }
bool getOutOfBand() const { return m_outOfBand; }
static MsgReportFreqOffset* create(int subChannelId, int freqOffset, bool outOfBand)
{
return new MsgReportFreqOffset(subChannelId, freqOffset, outOfBand);
}
private:
int m_subChannelId;
int m_freqOffset;
bool m_outOfBand;
MsgReportFreqOffset(int subChannelId, int freqOffset, bool outOfBand) :
Message(),
m_subChannelId(subChannelId),
m_freqOffset(freqOffset),
m_outOfBand(outOfBand)
{
}
};
class MsgReportIdent : public Message {
MESSAGE_CLASS_DECLARATION
@ -164,6 +138,26 @@ public:
{}
};
class MsgReportServiceddVORs : public Message {
MESSAGE_CLASS_DECLARATION
public:
std::vector<int>& getNavIds() { return m_navIds; }
QHash<int, bool>& getSinglePlans() { return m_singlePlans; }
static MsgReportServiceddVORs* create() {
return new MsgReportServiceddVORs();
}
private:
std::vector<int> m_navIds;
QHash<int, bool> m_singlePlans;
MsgReportServiceddVORs() :
Message()
{}
};
public:
VORLocalizerReport() {}
~VORLocalizerReport() {}

View File

@ -33,6 +33,8 @@ void VORLocalizerSettings::resetToDefaults()
m_rgbColor = QColor(255, 255, 0).rgb();
m_title = "VOR Localizer";
m_magDecAdjust = true;
m_rrTime = 20;
m_centerShift = 20000;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
@ -54,6 +56,8 @@ QByteArray VORLocalizerSettings::serialize() const
s.writeU32(7, m_rgbColor);
s.writeString(9, m_title);
s.writeBool(10, m_magDecAdjust);
s.writeS32(11, m_rrTime);
s.writeS32(12, m_centerShift);
s.writeBool(14, m_useReverseAPI);
s.writeString(15, m_reverseAPIAddress);
s.writeU32(16, m_reverseAPIPort);
@ -91,6 +95,8 @@ bool VORLocalizerSettings::deserialize(const QByteArray& data)
d.readU32(7, &m_rgbColor);
d.readString(9, &m_title, "VOR Localizer");
d.readBool(10, &m_magDecAdjust, true);
d.readS32(11, &m_rrTime, 20);
d.readS32(12, &m_centerShift, 20000);
d.readBool(14, &m_useReverseAPI, false);
d.readString(15, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(16, &utmp, 0);
@ -123,4 +129,14 @@ bool VORLocalizerSettings::deserialize(const QByteArray& data)
}
}
bool VORLocalizerSettings::VORChannel::operator<(const VORChannel& other) const
{
if (m_frequency != other.m_frequency) {
return m_frequency < other.m_frequency;
}
if (m_subChannelId != other.m_subChannelId) {
return m_subChannelId < other.m_subChannelId;
}
return false;
}

View File

@ -23,6 +23,7 @@
#include <QHash>
class Serializable;
class ChannelAPI;
// Number of columns in the table
@ -34,15 +35,38 @@ struct VORLocalizerSubChannelSettings {
struct VORLocalizerSettings
{
struct VORDemodChannels
struct VORChannel
{
int m_subChannelId; //!< Unique VOR identifier (from database)
int m_frequency; //!< Frequency the VOR is on
bool m_audioMute; //!< Mute the audio from this VOR
VORChannel() = default;
VORChannel(const VORChannel&) = default;
VORChannel& operator=(const VORChannel&) = default;
bool operator<(const VORChannel& other) const;
};
struct AvailableChannel
{
int m_deviceSetIndex;
int m_channelIndex;
ChannelAPI *m_channelAPI;
quint64 m_deviceCenterFrequency;
int m_basebandSampleRate;
int m_navId;
AvailableChannel() = default;
AvailableChannel(const AvailableChannel&) = default;
AvailableChannel& operator=(const AvailableChannel&) = default;
};
quint32 m_rgbColor;
QString m_title;
bool m_magDecAdjust; //!< Adjust for magnetic declination when drawing radials on the map
int m_rrTime; //!< Round robin turn time in seconds
int m_centerShift; //!< Center frequency shift to apply to move away from DC
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
@ -53,7 +77,7 @@ struct VORLocalizerSettings
static const int VORDEMOD_COLUMNS = 11;
static const int VOR_COL_NAME = 0;
static const int VOR_COL_FREQUENCY = 1;
static const int VOR_COL_OFFSET = 2;
static const int VOR_COL_NAVID = 2;
static const int VOR_COL_IDENT = 3;
static const int VOR_COL_MORSE = 4;
static const int VOR_COL_RX_IDENT = 5;
@ -66,7 +90,7 @@ struct VORLocalizerSettings
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
QHash<int, VORLocalizerSubChannelSettings *> m_subChannelSettings;
QHash<int, VORLocalizerSubChannelSettings> m_subChannelSettings;
VORLocalizerSettings();
void resetToDefaults();

View File

@ -18,12 +18,15 @@
#include <QDebug>
#include "SWGDeviceState.h"
#include "SWGDeviceSettings.h"
#include "SWGChannelSettings.h"
#include "SWGSuccessResponse.h"
#include "SWGErrorResponse.h"
#include "webapi/webapiadapterinterface.h"
#include "device/deviceset.h"
#include "channel/channelapi.h"
#include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h"
#include "maincore.h"
#include "vorlocalizerreport.h"
@ -36,7 +39,8 @@ class DSPDeviceSourceEngine;
VorLocalizerWorker::VorLocalizerWorker(WebAPIAdapterInterface *webAPIAdapterInterface) :
m_webAPIAdapterInterface(webAPIAdapterInterface),
m_msgQueueToGUI(nullptr),
m_msgQueueToFeature(nullptr),
m_availableChannels(nullptr),
m_running(false),
m_mutex(QMutex::Recursive)
{
@ -59,6 +63,8 @@ bool VorLocalizerWorker::startWork()
{
QMutexLocker mutexLocker(&m_mutex);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(&m_rrTimer, SIGNAL(timeout()), this, SLOT(rrNextTurn()));
m_rrTimer.start(m_settings.m_rrTime * 1000);
m_running = true;
return m_running;
}
@ -66,6 +72,8 @@ bool VorLocalizerWorker::startWork()
void VorLocalizerWorker::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
m_rrTimer.stop();
disconnect(&m_rrTimer, SIGNAL(timeout()), this, SLOT(rrNextTurn()));
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_running = false;
}
@ -98,6 +106,7 @@ bool VorLocalizerWorker::handleMessage(const Message& cmd)
{
qDebug() << "VorLocalizerWorker::handleMessage: MsgRefreshChannels";
updateChannels();
return true;
}
else
@ -124,28 +133,53 @@ void VorLocalizerWorker::applySettings(const VORLocalizerSettings& settings, boo
}
// Add new sub channels
QHash<int, VORLocalizerSubChannelSettings *>::const_iterator itr = settings.m_subChannelSettings.begin();
QHash<int, VORLocalizerSubChannelSettings>::const_iterator itr = settings.m_subChannelSettings.begin();
while (itr != settings.m_subChannelSettings.end())
{
VORLocalizerSubChannelSettings *subChannelSettings = itr.value();
const VORLocalizerSubChannelSettings& subChannelSettings = itr.value();
qDebug() << "VorLocalizerWorker::applySettings: subchannel " << subChannelSettings.m_id;
int j = 0;
for (; j < m_vorChannels.size(); j++)
{
if (subChannelSettings->m_id == m_vorChannels[j].m_subChannelId)
if (subChannelSettings.m_id == m_vorChannels[j].m_subChannelId)
{
qDebug() << "VorLocalizerWorker::applySettings: subchannel "
<< subChannelSettings.m_id
<< "already present";
break;
}
}
if (j == m_vorChannels.size())
{
// Add a sub-channel sink
qDebug() << "VorLocalizerWorker::applySettings: Adding sink " << subChannelSettings->m_id;
qDebug() << "VorLocalizerWorker::applySettings: Adding subchannel " << subChannelSettings.m_id;
addVORChannel(subChannelSettings);
}
++itr;
}
for (auto subChannelSetting : settings.m_subChannelSettings)
{
int navId = subChannelSetting.m_id;
if (m_settings.m_subChannelSettings.contains(navId))
{
if (subChannelSetting.m_audioMute != m_settings.m_subChannelSettings[navId].m_audioMute)
{
qDebug() << "VorLocalizerWorker::applySettings: audioMute:" << subChannelSetting.m_audioMute;
setAudioMute(navId, subChannelSetting.m_audioMute);
}
}
}
if ((settings.m_rrTime != m_settings.m_rrTime) || force) {
m_rrTimer.start(settings.m_rrTime * 1000);
}
m_settings = settings;
}
@ -159,6 +193,8 @@ void VorLocalizerWorker::updateHardware()
void VorLocalizerWorker::removeVORChannel(int navId)
{
qDebug("VorLocalizerWorker::removeVORChannel: %d", navId);
for (int i = 0; i < m_vorChannels.size(); i++)
{
if (m_vorChannels[i].m_subChannelId == navId)
@ -167,57 +203,538 @@ void VorLocalizerWorker::removeVORChannel(int navId)
break;
}
}
updateChannels();
}
void VorLocalizerWorker::addVORChannel(const VORLocalizerSubChannelSettings *subChannelSettings)
void VorLocalizerWorker::addVORChannel(const VORLocalizerSubChannelSettings& subChannelSettings)
{
VORChannel vorChannel = VORChannel{subChannelSettings->m_id, subChannelSettings->m_frequency, subChannelSettings->m_audioMute};
qDebug("VorLocalizerWorker::addVORChannel: %d at %d Hz",
subChannelSettings.m_id, subChannelSettings.m_frequency);
VORLocalizerSettings::VORChannel vorChannel =
VORLocalizerSettings::VORChannel{
subChannelSettings.m_id,
subChannelSettings.m_frequency,
subChannelSettings.m_audioMute
};
m_vorChannels.push_back(vorChannel);
updateChannels();
}
void VorLocalizerWorker::updateChannels()
{
MainCore *mainCore = MainCore::instance();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
std::vector<DeviceSet*>::const_iterator it = deviceSets.begin();
m_availableChannels.clear();
qDebug() << "VorLocalizerWorker::updateChannels: "
<< "#VORs:" << m_vorChannels.size()
<< "#Chans:" << m_availableChannels->size();
int deviceIndex = 0;
if ((m_vorChannels.size() == 0) || (m_availableChannels->size() == 0)) {
return;
}
for (; it != deviceSets.end(); ++it, deviceIndex++)
QMutexLocker mlock(&m_mutex);
std::sort(m_vorChannels.begin(), m_vorChannels.end());
std::vector<RRTurnPlan> devicesChannels;
getChannelsByDevice(m_availableChannels, devicesChannels);
QList<VORLocalizerSettings::VORChannel> unallocatedVORs(m_vorChannels);
m_rrPlans.clear();
int deviceCount = 0;
for (auto deviceChannel : devicesChannels)
{
DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
unsigned int nbChannels = unallocatedVORs.size() < (int) deviceChannel.m_channels.size() ?
unallocatedVORs.size() :
deviceChannel.m_channels.size();
std::vector<VORRange> vorRanges;
if (deviceSourceEngine)
while (nbChannels != 0)
{
for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++)
{
ChannelAPI *channel = (*it)->getChannelAt(chi);
getVORRanges(unallocatedVORs, nbChannels, vorRanges);
filterVORRanges(vorRanges, deviceChannel.m_bandwidth);
if (channel->getURI() == "sdrangel.channel.vordemodsc")
if (vorRanges.size() != 0) {
break;
}
nbChannels--;
}
std::vector<QList<VORLocalizerSettings::VORChannel>> vorLists;
for (auto vorRange : vorRanges)
{
QList<VORLocalizerSettings::VORChannel> vorList;
for (auto index : vorRange.m_vorIndices) {
vorList.append(VORLocalizerSettings::VORChannel(unallocatedVORs[index]));
}
vorLists.push_back(vorList);
}
// make one round robin turn for each VOR list for this device
std::vector<RRTurnPlan> rrDevicePlans;
for (auto vorList : vorLists)
{
RRTurnPlan turnPlan(deviceChannel);
int fMin = vorList.front().m_frequency;
int fMax = vorList.back().m_frequency;
int devFreq = (fMin + fMax) / 2;
turnPlan.m_device.m_frequency = devFreq;
int iCh = 0;
// qDebug() << "RR build plan "
// << "device:" << turnPlan.m_device.m_deviceIndex
// << "freq:" << turnPlan.m_device.m_frequency;
for (auto vorChannel : vorList)
{
RRChannel& channel = turnPlan.m_channels[iCh];
channel.m_frequencyShift = vorChannel.m_frequency - devFreq;
channel.m_navId = vorChannel.m_subChannelId;
// qDebug() << "VOR channel" << vorChannel.m_subChannelId
// << "freq:" << vorChannel.m_frequency
// << "channel:" << channel.m_channelIndex
// << "shift:" << channel.m_frequencyShift;
// remove VOR from the unallocated list
QList<VORLocalizerSettings::VORChannel>::iterator it = unallocatedVORs.begin();
while (it != unallocatedVORs.end())
{
AvailableChannel availableChannel = AvailableChannel{deviceIndex, chi, channel};
m_availableChannels.push_back(availableChannel);
if (it->m_subChannelId == vorChannel.m_subChannelId) {
it = unallocatedVORs.erase(it);
} else {
++it;
}
}
iCh++;
}
rrDevicePlans.push_back(turnPlan);
}
m_rrPlans.push_back(rrDevicePlans);
deviceCount++;
}
qDebug() << "VorLocalizerWorker::updateChannels: unallocatedVORs size:" << unallocatedVORs.size();
// Fallback for unallocated VORs: add single channel plans for all unallocated VORs
if ((unallocatedVORs.size() != 0) && (devicesChannels.size() != 0) && m_rrPlans.size() != 0)
{
VorLocalizerWorker::RRTurnPlan& deviceChannel = devicesChannels.front();
std::vector<VORRange> vorRanges;
getVORRanges(unallocatedVORs, 1, vorRanges);
std::vector<VorLocalizerWorker::RRTurnPlan>& rrPlan = m_rrPlans.front();
std::vector<QList<VORLocalizerSettings::VORChannel>> vorLists;
for (auto vorRange : vorRanges)
{
QList<VORLocalizerSettings::VORChannel> vorList;
for (auto index : vorRange.m_vorIndices) {
vorList.append(VORLocalizerSettings::VORChannel(unallocatedVORs[index]));
}
vorLists.push_back(vorList);
}
for (auto vorList : vorLists)
{
RRTurnPlan turnPlan(deviceChannel);
int fMin = vorList.front().m_frequency;
int fMax = vorList.back().m_frequency;
int devFreq = (fMin + fMax) / 2;
turnPlan.m_device.m_frequency = devFreq;
int iCh = 0;
// qDebug() << "RR build plan "
// << "device:" << turnPlan.m_device.m_deviceIndex
// << "freq:" << turnPlan.m_device.m_frequency;
for (auto vorChannel : vorList)
{
RRChannel& channel = turnPlan.m_channels[iCh];
channel.m_frequencyShift = vorChannel.m_frequency - devFreq;
channel.m_navId = vorChannel.m_subChannelId;
// qDebug() << "VOR channel" << vorChannel.m_subChannelId
// << "freq:" << vorChannel.m_frequency
// << "channel:" << channel.m_channelIndex
// << "shift:" << channel.m_frequencyShift;
iCh++;
}
rrPlan.push_back(turnPlan);
}
}
for (auto rrPlans : m_rrPlans)
{
qDebug() << "VorLocalizerWorker::updateChannels: RR plans for one device";
for (auto rrPlan : rrPlans)
{
qDebug() << "VorLocalizerWorker::updateChannels: RR plan: "
<< "device:" << rrPlan.m_device.m_deviceIndex
<< "frequency:" << rrPlan.m_device.m_frequency;
for (auto rrChannel : rrPlan.m_channels)
{
qDebug() << "VorLocalizerWorker::updateChannels: RR channel: "
<< "channel:" << rrChannel.m_channelAPI
<< "index:" << rrChannel.m_channelIndex
<< "shift:" << rrChannel.m_frequencyShift
<< "navId:" << rrChannel.m_navId;
}
}
}
if (m_msgQueueToGUI)
m_rrTurnCounters.resize(deviceCount);
std::fill(m_rrTurnCounters.begin(), m_rrTurnCounters.end(), 0);
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)
{
VORLocalizerReport::MsgReportChannels *msg = VORLocalizerReport::MsgReportChannels::create();
std::vector<VORLocalizerReport::MsgReportChannels::Channel>& msgChannels = msg->getChannels();
qWarning("VorLocalizerWorker::setDeviceFrequency: get device frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
}
for (int i = 0; i < m_availableChannels.size(); i++)
{
VORLocalizerReport::MsgReportChannels::Channel msgChannel =
VORLocalizerReport::MsgReportChannels::Channel{
m_availableChannels[i].m_deviceSetIndex,
m_availableChannels[i].m_channelIndex
};
msgChannels.push_back(msgChannel);
}
QJsonObject *jsonObj = deviceSettingsResponse.asJsonObject();
m_msgQueueToGUI->push(msg);
// 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)
{
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC;
// Get channel settings containg inputFrequencyOffset, so we can patch them
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsGet(
deviceIndex,
channelIndex,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("VorLocalizerWorker::setChannelShift: get channel offset frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
}
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
if (!WebAPIUtils::setSubObjectDouble(*jsonObj, "inputFrequencyOffset", targetOffset))
{
qWarning("VorLocalizerWorker::setChannelShift: No inputFrequencyOffset key in channel settings");
return;
}
if (!WebAPIUtils::setSubObjectInt(*jsonObj, "navId", vorNavId))
{
qWarning("VorLocalizerWorker::setChannelShift: No navId key in channel settings");
return;
}
QStringList channelSettingsKeys;
if (m_settings.m_subChannelSettings.contains(vorNavId))
{
if (!WebAPIUtils::setSubObjectInt(*jsonObj, "audioMute", m_settings.m_subChannelSettings[vorNavId].m_audioMute ? 1 : 0)) {
qWarning("VorLocalizerWorker::setChannelShift: No audioMute key in channel settings");
} else {
channelSettingsKeys.append("audioMute");
}
}
channelSettingsKeys.append("inputFrequencyOffset");
channelSettingsKeys.append("navId");
channelSettingsResponse.init();
channelSettingsResponse.fromJsonObject(*jsonObj);
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsPutPatch(
deviceIndex,
channelIndex,
false, // PATCH
channelSettingsKeys,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 == 2)
{
qDebug("VorLocalizerWorker::setChannelShift: inputFrequencyOffset: %f navId: %d OK", targetOffset, vorNavId);
}
else
{
qWarning("VorLocalizerWorker::setChannelShift: set inputFrequencyOffset and navId error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
}
}
void VorLocalizerWorker::setAudioMute(int vorNavId, bool audioMute)
{
QMutexLocker mlock(&m_mutex);
if (!m_channelAllocations.contains(vorNavId)) {
return;
}
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC;
int deviceIndex = m_channelAllocations[vorNavId].m_deviceIndex;
int channelIndex = m_channelAllocations[vorNavId].m_channelIndex;
// Get channel settings containg inputFrequencyOffset, so we can patch them
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsGet(
deviceIndex,
channelIndex,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("VorLocalizerWorker::setChannelShift: get channel offset frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
}
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
if (!WebAPIUtils::setSubObjectInt(*jsonObj, "audioMute", audioMute ? 1 : 0))
{
qWarning("VorLocalizerWorker::setAudioMute: No audioMute key in channel settings");
return;
}
QStringList channelSettingsKeys;
channelSettingsKeys.append("audioMute");
channelSettingsResponse.init();
channelSettingsResponse.fromJsonObject(*jsonObj);
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsPutPatch(
deviceIndex,
channelIndex,
false, // PATCH
channelSettingsKeys,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 == 2)
{
qDebug("VorLocalizerWorker::setAudioMute: navId: %d audioMute: %d OK", vorNavId, audioMute ? 1 : 0);
}
else
{
qWarning("VorLocalizerWorker::setAudioMute: navId: %d set audioMute error %d: %s",
vorNavId, httpRC, qPrintable(*errorResponse.getMessage()));
}
}
void VorLocalizerWorker::generateIndexCombinations(int length, int subLength, std::vector<std::vector<int>>& indexCombinations)
{
indexCombinations.clear();
std::vector<int> sublist(subLength);
std::vector<int>::iterator first = sublist.begin(), last = sublist.end();
std::iota(first, last, 0);
indexCombinations.push_back(sublist);
while ((*first) != length - subLength)
{
std::vector<int>::iterator mt = last;
while (*(--mt) == length-(last-mt));
(*mt)++;
while (++mt != last) *mt = *(mt-1)+1;
indexCombinations.push_back(std::vector<int>(first, last));
}
}
void VorLocalizerWorker::getVORRanges(const QList<VORLocalizerSettings::VORChannel>& vors, int subLength, std::vector<VORRange>& vorRanges)
{
std::vector<std::vector<int>> indexCombinations;
generateIndexCombinations(vors.size(), subLength, indexCombinations);
vorRanges.clear();
for (auto indexCombination : indexCombinations)
{
int fMax = vors.at(indexCombination.back()).m_frequency;
int fMin = vors.at(indexCombination.front()).m_frequency;
vorRanges.push_back(VORRange{indexCombination, fMax - fMin});
}
}
void VorLocalizerWorker::filterVORRanges(std::vector<VORRange>& vorRanges, int thresholdBW)
{
std::vector<VORRange> originalVORRanges(vorRanges.size());
std::copy(vorRanges.begin(), vorRanges.end(), originalVORRanges.begin());
vorRanges.clear();
for (auto vorRange : originalVORRanges)
{
if (vorRange.m_frequencyRange < thresholdBW) {
vorRanges.push_back(vorRange);
}
}
}
void VorLocalizerWorker::getChannelsByDevice(
const QHash<ChannelAPI*, VORLocalizerSettings::AvailableChannel> *availableChannels,
std::vector<RRTurnPlan>& devicesChannels
)
{
struct
{
bool operator()(const RRTurnPlan& a, const RRTurnPlan& b)
{
unsigned int nbChannelsA = a.m_channels.size();
unsigned int nbChannelsB = a.m_channels.size();
if (nbChannelsA == nbChannelsB) {
return a.m_bandwidth > b.m_bandwidth;
} else {
return nbChannelsA > nbChannelsB;
}
}
} rrTurnPlanGreater;
QHash<ChannelAPI*, VORLocalizerSettings::AvailableChannel>::const_iterator itr = availableChannels->begin();
QMap<int, RRTurnPlan> devicesChannelsMap;
for (; itr != availableChannels->end(); ++itr)
{
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_channels.push_back(RRChannel{itr->m_channelAPI, itr->m_channelIndex, 0, -1});
}
QMap<int, RRTurnPlan>::const_iterator itm = devicesChannelsMap.begin();
devicesChannels.clear();
for (; itm != devicesChannelsMap.end(); ++itm) {
devicesChannels.push_back(*itm);
}
std::sort(devicesChannels.begin(), devicesChannels.end(), rrTurnPlanGreater);
}
void VorLocalizerWorker::rrNextTurn()
{
QMutexLocker mlock(&m_mutex);
int iDevPlan = 0;
VORLocalizerReport::MsgReportServiceddVORs *msg = VORLocalizerReport::MsgReportServiceddVORs::create();
m_channelAllocations.clear();
for (auto rrPlan : m_rrPlans)
{
unsigned int turnCount = m_rrTurnCounters[iDevPlan];
int deviceIndex = rrPlan[turnCount].m_device.m_deviceIndex;
int deviceFrequency = rrPlan[turnCount].m_device.m_frequency - m_settings.m_centerShift;
qDebug() << "VorLocalizerWorker::rrNextTurn: "
<< "turn:" << turnCount
<< "device:" << deviceIndex
<< "frequency:" << deviceFrequency - m_settings.m_centerShift;
setDeviceFrequency(deviceIndex, deviceFrequency);
for (auto channel : rrPlan[turnCount].m_channels)
{
qDebug() << "VorLocalizerWorker::rrNextTurn: "
<< "device:" << deviceIndex
<< "channel:" << channel.m_channelIndex
<< "shift:" << channel.m_frequencyShift + m_settings.m_centerShift
<< "navId:" << channel.m_navId;
setChannelShift(
deviceIndex,
channel.m_channelIndex,
channel.m_frequencyShift + m_settings.m_centerShift,
channel.m_navId
);
m_channelAllocations[channel.m_navId] = ChannelAllocation{
channel.m_navId,
deviceIndex,
channel.m_channelIndex
};
if(m_availableChannels->contains(channel.m_channelAPI))
{
VORLocalizerSettings::AvailableChannel& availableChannel = m_availableChannels->operator[](channel.m_channelAPI);
availableChannel.m_navId = channel.m_navId;
}
msg->getNavIds().push_back(channel.m_navId);
msg->getSinglePlans()[channel.m_navId] = (rrPlan.size() == 1);
}
turnCount++;
if (turnCount == rrPlan.size()) {
turnCount = 0;
}
m_rrTurnCounters[iDevPlan] = turnCount;
iDevPlan++;
}
if (m_msgQueueToFeature) {
m_msgQueueToFeature->push(msg);
}
}

View File

@ -28,6 +28,7 @@
class WebAPIAdapterInterface;
class ChannelAPI;
class Feature;
class VorLocalizerWorker : public QObject
{
@ -77,42 +78,98 @@ public:
void stopWork();
bool isRunning() const { return m_running; }
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; }
void setMessageQueueToFeature(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; }
void setAvailableChannels(QHash<ChannelAPI*, VORLocalizerSettings::AvailableChannel> *avaialbleChannels) {
m_availableChannels = avaialbleChannels;
}
private:
struct VORChannel
struct VORRange
{
int m_subChannelId; //!< Unique VOR identifier (from database)
int m_frequency; //!< Frequency the VOR is on
bool m_audioMute; //!< Mute the audio from this VOR
std::vector<int> m_vorIndices;
int m_frequencyRange;
VORRange() = default;
VORRange(const VORRange&) = default;
VORRange& operator=(const VORRange&) = default;
};
struct AvailableChannel
struct RRDevice
{
int m_deviceIndex;
int m_frequency;
RRDevice() = default;
RRDevice(const RRDevice&) = default;
RRDevice& operator=(const RRDevice&) = default;
};
struct RRChannel
{
int m_deviceSetIndex;
int m_channelIndex;
ChannelAPI *m_channelAPI;
int m_channelIndex;
int m_frequencyShift;
int m_navId;
RRChannel() = default;
RRChannel(const RRChannel&) = default;
RRChannel& operator=(const RRChannel&) = default;
};
struct RRTurnPlan
{
RRDevice m_device;
int m_bandwidth;
std::vector<RRChannel> m_channels;
RRTurnPlan() = default;
RRTurnPlan(const RRTurnPlan&) = default;
RRTurnPlan& operator=(const RRTurnPlan&) = default;
};
struct ChannelAllocation
{
int m_navId;
int m_deviceIndex;
int m_channelIndex;
ChannelAllocation() = default;
ChannelAllocation(const ChannelAllocation&) = default;
ChannelAllocation& operator=(const ChannelAllocation&) = default;
};
WebAPIAdapterInterface *m_webAPIAdapterInterface;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
MessageQueue *m_msgQueueToGUI; //!< Queue to report state to GUI
MessageQueue *m_msgQueueToFeature; //!< Queue to report state to GUI
VORLocalizerSettings m_settings;
QList<VORChannel> m_vorChannels;
QList<AvailableChannel> m_availableChannels;
QList<VORLocalizerSettings::VORChannel> m_vorChannels;
QHash<int, ChannelAllocation> m_channelAllocations;
QHash<ChannelAPI*, VORLocalizerSettings::AvailableChannel> *m_availableChannels;
bool m_running;
QTimer m_updateTimer;
QMutex m_mutex;
QTimer m_rrTimer;
std::vector<std::vector<RRTurnPlan>> m_rrPlans; //!< Round robin plans for each device
std::vector<int> m_rrTurnCounters; //!< Round robin turn count for each device
bool handleMessage(const Message& cmd);
void applySettings(const VORLocalizerSettings& settings, bool force = false);
void updateChannels();
void removeVORChannel(int navId);
void addVORChannel(const VORLocalizerSubChannelSettings *subChannelSettings);
void addVORChannel(const VORLocalizerSubChannelSettings& subChannelSettings);
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 setAudioMute(int vorNavId, bool audioMute);
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 filterVORRanges(std::vector<VORRange>& vorRanges, int thresholdBW);
static void getChannelsByDevice(const QHash<ChannelAPI*, VORLocalizerSettings::AvailableChannel> *availableChannels, std::vector<RRTurnPlan>& m_deviceChannels);
private slots:
void handleInputMessages();
void updateHardware();
void rrNextTurn();
};
#endif // INCLUDE_FEATURE_VORLOCALIZERWORKER_H_

View File

@ -46,7 +46,7 @@ MessagePipes::~MessagePipes()
}
}
void MessagePipes::registerChannelToFeature(const ChannelAPI *source, const Feature *feature, const QString& type)
MessageQueue *MessagePipes::registerChannelToFeature(const ChannelAPI *source, const Feature *feature, const QString& type)
{
int typeId;
@ -68,8 +68,11 @@ void MessagePipes::registerChannelToFeature(const ChannelAPI *source, const Feat
m_featureRegistrations.insert(regKey, QList<const Feature*>());
}
m_messageRegistrations[regKey].append(new MessageQueue());
MessageQueue *messageQueue = new MessageQueue();
m_messageRegistrations[regKey].append(messageQueue);
m_featureRegistrations[regKey].append(feature);
return messageQueue;
}
QList<MessageQueue*>* MessagePipes::getMessageQueues(const ChannelAPI *source, const QString& type)

View File

@ -45,7 +45,7 @@ public:
MessagePipes& operator=(const MessagePipes&) = delete;
~MessagePipes();
void registerChannelToFeature(const ChannelAPI *source, const Feature *feature, const QString& type);
MessageQueue *registerChannelToFeature(const ChannelAPI *source, const Feature *feature, const QString& type);
QList<MessageQueue*>* getMessageQueues(const ChannelAPI *source, const QString& type);
private:

View File

@ -9484,20 +9484,36 @@ margin-bottom: 20px;
"type" : "number",
"format" : "float"
},
"navId" : {
"type" : "integer",
"description" : "VOR unique identifier when set by VOR localizer feature"
},
"radial" : {
"type" : "number",
"format" : "float",
"description" : "current detected radial"
"description" : "current detected radial (degrees)"
},
"refMag" : {
"type" : "number",
"format" : "float",
"description" : "current reference signal magnitude"
"description" : "current reference signal magnitude (dB)"
},
"varMag" : {
"type" : "number",
"format" : "float",
"description" : "current variable signal magnitude"
"description" : "current variable signal magnitude (dB)"
},
"validRadial" : {
"type" : "integer",
"description" : "Radial validity estimation\n * 0 - Radial is invalid\n * 1 - Radial is valid\n"
},
"validRefMag" : {
"type" : "integer",
"description" : "Reference signal magnitude validity\n * 0 - Magnitude below threshold\n * 1 - Magnitude above threshold\n"
},
"validVarMag" : {
"type" : "integer",
"description" : "Variable signal magnitude validity\n * 0 - Magnitude below threshold\n * 1 - Magnitude above threshold\n"
},
"morseIdent" : {
"type" : "string",
@ -9645,6 +9661,14 @@ margin-bottom: 20px;
"magDecAdjust" : {
"type" : "integer",
"description" : "Adjust radial lines on map for magnetic declination of VOR"
},
"rrTime" : {
"type" : "integer",
"description" : "Round robin turn time in seconds"
},
"centerShift" : {
"type" : "integer",
"description" : "Shift of center frequency in Hz"
}
},
"description" : "VORLocalizer"
@ -44850,7 +44874,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-11-29T21:00:18.945+01:00
Generated 2020-12-06T23:43:21.772+01:00
</div>
</div>
</div>

View File

@ -55,18 +55,39 @@ VORDemodSCReport:
volume:
type: number
format: float
navId:
description: VOR unique identifier when set by VOR localizer feature
type: integer
radial:
description: current detected radial
description: current detected radial (degrees)
type: number
format: float
refMag:
description: current reference signal magnitude
description: current reference signal magnitude (dB)
type: number
format: float
varMag:
description: current variable signal magnitude
description: current variable signal magnitude (dB)
type: number
format: float
validRadial:
type: integer
description: >
Radial validity estimation
* 0 - Radial is invalid
* 1 - Radial is valid
validRefMag:
type: integer
description: >
Reference signal magnitude validity
* 0 - Magnitude below threshold
* 1 - Magnitude above threshold
validVarMag:
type: integer
description: >
Variable signal magnitude validity
* 0 - Magnitude below threshold
* 1 - Magnitude above threshold
morseIdent:
description: current identification morse code transcript
type: string

View File

@ -19,3 +19,9 @@ VORLocalizerSettings:
magDecAdjust:
description: Adjust radial lines on map for magnetic declination of VOR
type: integer
rrTime:
description: Round robin turn time in seconds
type: integer
centerShift:
description: Shift of center frequency in Hz
type: integer

59
sdrbase/util/average.h Normal file
View File

@ -0,0 +1,59 @@
///////////////////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// 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 _UTIL_AVERAGE_H_
#define _UTIL_AVERAGE_H_
#include <algorithm>
template <typename T, typename Total>
class AverageUtil
{
public:
AverageUtil()
: m_numSamples(0), m_total(0)
{ }
AverageUtil(T sample)
: m_numSamples(1), m_total(sample)
{ }
void reset()
{
m_numSamples = 0;
m_total = 0;
}
void operator()(T sample)
{
m_total += sample;
m_numSamples++;
}
double asDouble() const { return ((double)m_total) / (m_numSamples == 0 ? 1 : m_numSamples); }
float asFloat() const { return ((float)m_total) / (m_numSamples == 0 ? 1 : m_numSamples); }
operator T() const { return m_total / (m_numSamples == 0 ? 1 : m_numSamples); }
T instantAverage() const { return m_total / (m_numSamples == 0 ? 1 : m_numSamples); }
int getNumSamples() const { return m_numSamples; }
private:
int m_numSamples;
Total m_total;
};
#endif /* _UTIL_AVERAGE_H_ */

View File

@ -344,6 +344,51 @@ bool WebAPIUtils::setSubObjectDouble(QJsonObject &json, const QString &key, doub
return false;
}
// Get integer value from within nested JSON object
bool WebAPIUtils::getSubObjectInt(const QJsonObject &json, const QString &key, int &value)
{
for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++)
{
QJsonValue jsonValue = it.value();
if (jsonValue.isObject())
{
QJsonObject subObject = jsonValue.toObject();
if (subObject.contains(key))
{
value = subObject[key].toInt();
return true;
}
}
}
return false;
}
// Set integer value withing nested JSON object
bool WebAPIUtils::setSubObjectInt(QJsonObject &json, const QString &key, int value)
{
for (QJsonObject::iterator it = json.begin(); it != json.end(); it++)
{
QJsonValue jsonValue = it.value();
if (jsonValue.isObject())
{
QJsonObject subObject = jsonValue.toObject();
if (subObject.contains(key))
{
subObject[key] = value;
it.value() = subObject;
return true;
}
}
}
return false;
}
// look for value in key=value
bool WebAPIUtils::extractValue(const QJsonObject &json, const QString &key, QJsonValue &value)
{

View File

@ -47,6 +47,8 @@ public:
static bool getObjectObjects(const QJsonObject &json, const QString &key, QList<QJsonObject> &objects);
static bool getSubObjectDouble(const QJsonObject &json, const QString &key, double &value);
static bool setSubObjectDouble(QJsonObject &json, const QString &key, double value);
static bool getSubObjectInt(const QJsonObject &json, const QString &key, int &value);
static bool setSubObjectInt(QJsonObject &json, const QString &key, int value);
static bool extractValue(const QJsonObject &json, const QString &key, QJsonValue &value);
static bool extractArray(const QJsonObject &json, const QString &key, QJsonArray &value);
static bool extractObject(const QJsonObject &json, const QString &key, QJsonObject &value);

View File

@ -55,18 +55,39 @@ VORDemodSCReport:
volume:
type: number
format: float
navId:
description: VOR unique identifier when set by VOR localizer feature
type: integer
radial:
description: current detected radial
description: current detected radial (degrees)
type: number
format: float
refMag:
description: current reference signal magnitude
description: current reference signal magnitude (dB)
type: number
format: float
varMag:
description: current variable signal magnitude
description: current variable signal magnitude (dB)
type: number
format: float
validRadial:
type: integer
description: >
Radial validity estimation
* 0 - Radial is invalid
* 1 - Radial is valid
validRefMag:
type: integer
description: >
Reference signal magnitude validity
* 0 - Magnitude below threshold
* 1 - Magnitude above threshold
validVarMag:
type: integer
description: >
Variable signal magnitude validity
* 0 - Magnitude below threshold
* 1 - Magnitude above threshold
morseIdent:
description: current identification morse code transcript
type: string

View File

@ -19,3 +19,9 @@ VORLocalizerSettings:
magDecAdjust:
description: Adjust radial lines on map for magnetic declination of VOR
type: integer
rrTime:
description: Round robin turn time in seconds
type: integer
centerShift:
description: Shift of center frequency in Hz
type: integer

View File

@ -9484,20 +9484,36 @@ margin-bottom: 20px;
"type" : "number",
"format" : "float"
},
"navId" : {
"type" : "integer",
"description" : "VOR unique identifier when set by VOR localizer feature"
},
"radial" : {
"type" : "number",
"format" : "float",
"description" : "current detected radial"
"description" : "current detected radial (degrees)"
},
"refMag" : {
"type" : "number",
"format" : "float",
"description" : "current reference signal magnitude"
"description" : "current reference signal magnitude (dB)"
},
"varMag" : {
"type" : "number",
"format" : "float",
"description" : "current variable signal magnitude"
"description" : "current variable signal magnitude (dB)"
},
"validRadial" : {
"type" : "integer",
"description" : "Radial validity estimation\n * 0 - Radial is invalid\n * 1 - Radial is valid\n"
},
"validRefMag" : {
"type" : "integer",
"description" : "Reference signal magnitude validity\n * 0 - Magnitude below threshold\n * 1 - Magnitude above threshold\n"
},
"validVarMag" : {
"type" : "integer",
"description" : "Variable signal magnitude validity\n * 0 - Magnitude below threshold\n * 1 - Magnitude above threshold\n"
},
"morseIdent" : {
"type" : "string",
@ -9645,6 +9661,14 @@ margin-bottom: 20px;
"magDecAdjust" : {
"type" : "integer",
"description" : "Adjust radial lines on map for magnetic declination of VOR"
},
"rrTime" : {
"type" : "integer",
"description" : "Round robin turn time in seconds"
},
"centerShift" : {
"type" : "integer",
"description" : "Shift of center frequency in Hz"
}
},
"description" : "VORLocalizer"
@ -44850,7 +44874,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-11-29T21:00:18.945+01:00
Generated 2020-12-06T23:43:21.772+01:00
</div>
</div>
</div>

View File

@ -36,12 +36,20 @@ SWGVORDemodSCReport::SWGVORDemodSCReport() {
m_audio_sample_rate_isSet = false;
volume = 0.0f;
m_volume_isSet = false;
nav_id = 0;
m_nav_id_isSet = false;
radial = 0.0f;
m_radial_isSet = false;
ref_mag = 0.0f;
m_ref_mag_isSet = false;
var_mag = 0.0f;
m_var_mag_isSet = false;
valid_radial = 0;
m_valid_radial_isSet = false;
valid_ref_mag = 0;
m_valid_ref_mag_isSet = false;
valid_var_mag = 0;
m_valid_var_mag_isSet = false;
morse_ident = nullptr;
m_morse_ident_isSet = false;
}
@ -60,12 +68,20 @@ SWGVORDemodSCReport::init() {
m_audio_sample_rate_isSet = false;
volume = 0.0f;
m_volume_isSet = false;
nav_id = 0;
m_nav_id_isSet = false;
radial = 0.0f;
m_radial_isSet = false;
ref_mag = 0.0f;
m_ref_mag_isSet = false;
var_mag = 0.0f;
m_var_mag_isSet = false;
valid_radial = 0;
m_valid_radial_isSet = false;
valid_ref_mag = 0;
m_valid_ref_mag_isSet = false;
valid_var_mag = 0;
m_valid_var_mag_isSet = false;
morse_ident = new QString("");
m_morse_ident_isSet = false;
}
@ -79,6 +95,10 @@ SWGVORDemodSCReport::cleanup() {
if(morse_ident != nullptr) {
delete morse_ident;
}
@ -103,12 +123,20 @@ SWGVORDemodSCReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&volume, pJson["volume"], "float", "");
::SWGSDRangel::setValue(&nav_id, pJson["navId"], "qint32", "");
::SWGSDRangel::setValue(&radial, pJson["radial"], "float", "");
::SWGSDRangel::setValue(&ref_mag, pJson["refMag"], "float", "");
::SWGSDRangel::setValue(&var_mag, pJson["varMag"], "float", "");
::SWGSDRangel::setValue(&valid_radial, pJson["validRadial"], "qint32", "");
::SWGSDRangel::setValue(&valid_ref_mag, pJson["validRefMag"], "qint32", "");
::SWGSDRangel::setValue(&valid_var_mag, pJson["validVarMag"], "qint32", "");
::SWGSDRangel::setValue(&morse_ident, pJson["morseIdent"], "QString", "QString");
}
@ -139,6 +167,9 @@ SWGVORDemodSCReport::asJsonObject() {
if(m_volume_isSet){
obj->insert("volume", QJsonValue(volume));
}
if(m_nav_id_isSet){
obj->insert("navId", QJsonValue(nav_id));
}
if(m_radial_isSet){
obj->insert("radial", QJsonValue(radial));
}
@ -148,6 +179,15 @@ SWGVORDemodSCReport::asJsonObject() {
if(m_var_mag_isSet){
obj->insert("varMag", QJsonValue(var_mag));
}
if(m_valid_radial_isSet){
obj->insert("validRadial", QJsonValue(valid_radial));
}
if(m_valid_ref_mag_isSet){
obj->insert("validRefMag", QJsonValue(valid_ref_mag));
}
if(m_valid_var_mag_isSet){
obj->insert("validVarMag", QJsonValue(valid_var_mag));
}
if(morse_ident != nullptr && *morse_ident != QString("")){
toJsonValue(QString("morseIdent"), morse_ident, obj, QString("QString"));
}
@ -195,6 +235,16 @@ SWGVORDemodSCReport::setVolume(float volume) {
this->m_volume_isSet = true;
}
qint32
SWGVORDemodSCReport::getNavId() {
return nav_id;
}
void
SWGVORDemodSCReport::setNavId(qint32 nav_id) {
this->nav_id = nav_id;
this->m_nav_id_isSet = true;
}
float
SWGVORDemodSCReport::getRadial() {
return radial;
@ -225,6 +275,36 @@ SWGVORDemodSCReport::setVarMag(float var_mag) {
this->m_var_mag_isSet = true;
}
qint32
SWGVORDemodSCReport::getValidRadial() {
return valid_radial;
}
void
SWGVORDemodSCReport::setValidRadial(qint32 valid_radial) {
this->valid_radial = valid_radial;
this->m_valid_radial_isSet = true;
}
qint32
SWGVORDemodSCReport::getValidRefMag() {
return valid_ref_mag;
}
void
SWGVORDemodSCReport::setValidRefMag(qint32 valid_ref_mag) {
this->valid_ref_mag = valid_ref_mag;
this->m_valid_ref_mag_isSet = true;
}
qint32
SWGVORDemodSCReport::getValidVarMag() {
return valid_var_mag;
}
void
SWGVORDemodSCReport::setValidVarMag(qint32 valid_var_mag) {
this->valid_var_mag = valid_var_mag;
this->m_valid_var_mag_isSet = true;
}
QString*
SWGVORDemodSCReport::getMorseIdent() {
return morse_ident;
@ -252,6 +332,9 @@ SWGVORDemodSCReport::isSet(){
if(m_volume_isSet){
isObjectUpdated = true; break;
}
if(m_nav_id_isSet){
isObjectUpdated = true; break;
}
if(m_radial_isSet){
isObjectUpdated = true; break;
}
@ -261,6 +344,15 @@ SWGVORDemodSCReport::isSet(){
if(m_var_mag_isSet){
isObjectUpdated = true; break;
}
if(m_valid_radial_isSet){
isObjectUpdated = true; break;
}
if(m_valid_ref_mag_isSet){
isObjectUpdated = true; break;
}
if(m_valid_var_mag_isSet){
isObjectUpdated = true; break;
}
if(morse_ident && *morse_ident != QString("")){
isObjectUpdated = true; break;
}

View File

@ -54,6 +54,9 @@ public:
float getVolume();
void setVolume(float volume);
qint32 getNavId();
void setNavId(qint32 nav_id);
float getRadial();
void setRadial(float radial);
@ -63,6 +66,15 @@ public:
float getVarMag();
void setVarMag(float var_mag);
qint32 getValidRadial();
void setValidRadial(qint32 valid_radial);
qint32 getValidRefMag();
void setValidRefMag(qint32 valid_ref_mag);
qint32 getValidVarMag();
void setValidVarMag(qint32 valid_var_mag);
QString* getMorseIdent();
void setMorseIdent(QString* morse_ident);
@ -82,6 +94,9 @@ private:
float volume;
bool m_volume_isSet;
qint32 nav_id;
bool m_nav_id_isSet;
float radial;
bool m_radial_isSet;
@ -91,6 +106,15 @@ private:
float var_mag;
bool m_var_mag_isSet;
qint32 valid_radial;
bool m_valid_radial_isSet;
qint32 valid_ref_mag;
bool m_valid_ref_mag_isSet;
qint32 valid_var_mag;
bool m_valid_var_mag_isSet;
QString* morse_ident;
bool m_morse_ident_isSet;

View File

@ -44,6 +44,10 @@ SWGVORLocalizerSettings::SWGVORLocalizerSettings() {
m_reverse_api_feature_index_isSet = false;
mag_dec_adjust = 0;
m_mag_dec_adjust_isSet = false;
rr_time = 0;
m_rr_time_isSet = false;
center_shift = 0;
m_center_shift_isSet = false;
}
SWGVORLocalizerSettings::~SWGVORLocalizerSettings() {
@ -68,6 +72,10 @@ SWGVORLocalizerSettings::init() {
m_reverse_api_feature_index_isSet = false;
mag_dec_adjust = 0;
m_mag_dec_adjust_isSet = false;
rr_time = 0;
m_rr_time_isSet = false;
center_shift = 0;
m_center_shift_isSet = false;
}
void
@ -84,6 +92,8 @@ SWGVORLocalizerSettings::cleanup() {
}
SWGVORLocalizerSettings*
@ -113,6 +123,10 @@ SWGVORLocalizerSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&mag_dec_adjust, pJson["magDecAdjust"], "qint32", "");
::SWGSDRangel::setValue(&rr_time, pJson["rrTime"], "qint32", "");
::SWGSDRangel::setValue(&center_shift, pJson["centerShift"], "qint32", "");
}
QString
@ -153,6 +167,12 @@ SWGVORLocalizerSettings::asJsonObject() {
if(m_mag_dec_adjust_isSet){
obj->insert("magDecAdjust", QJsonValue(mag_dec_adjust));
}
if(m_rr_time_isSet){
obj->insert("rrTime", QJsonValue(rr_time));
}
if(m_center_shift_isSet){
obj->insert("centerShift", QJsonValue(center_shift));
}
return obj;
}
@ -237,6 +257,26 @@ SWGVORLocalizerSettings::setMagDecAdjust(qint32 mag_dec_adjust) {
this->m_mag_dec_adjust_isSet = true;
}
qint32
SWGVORLocalizerSettings::getRrTime() {
return rr_time;
}
void
SWGVORLocalizerSettings::setRrTime(qint32 rr_time) {
this->rr_time = rr_time;
this->m_rr_time_isSet = true;
}
qint32
SWGVORLocalizerSettings::getCenterShift() {
return center_shift;
}
void
SWGVORLocalizerSettings::setCenterShift(qint32 center_shift) {
this->center_shift = center_shift;
this->m_center_shift_isSet = true;
}
bool
SWGVORLocalizerSettings::isSet(){
@ -266,6 +306,12 @@ SWGVORLocalizerSettings::isSet(){
if(m_mag_dec_adjust_isSet){
isObjectUpdated = true; break;
}
if(m_rr_time_isSet){
isObjectUpdated = true; break;
}
if(m_center_shift_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}

View File

@ -66,6 +66,12 @@ public:
qint32 getMagDecAdjust();
void setMagDecAdjust(qint32 mag_dec_adjust);
qint32 getRrTime();
void setRrTime(qint32 rr_time);
qint32 getCenterShift();
void setCenterShift(qint32 center_shift);
virtual bool isSet() override;
@ -94,6 +100,12 @@ private:
qint32 mag_dec_adjust;
bool m_mag_dec_adjust_isSet;
qint32 rr_time;
bool m_rr_time_isSet;
qint32 center_shift;
bool m_center_shift_isSet;
};
}