2020-11-30 01:30:18 +01:00
///////////////////////////////////////////////////////////////////////////////////
2023-11-18 13:12:18 +01:00
// Copyright (C) 2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2021-2022 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2022 Jiří Pinkava <jiri.pinkava@rossum.ai> //
2020-11-30 01:30:18 +01:00
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
2020-12-07 19:32:43 +01:00
#include "SWGChannelSettings.h"
2020-11-30 01:30:18 +01:00
#include "SWGSuccessResponse.h"
#include "SWGErrorResponse.h"
#include "device/deviceset.h"
2022-05-04 08:27:25 +01:00
#include "device/deviceapi.h"
#include "dsp/devicesamplesource.h"
#include "dsp/devicesamplesink.h"
2020-11-30 01:30:18 +01:00
#include "channel/channelapi.h"
2022-05-04 08:27:25 +01:00
#include "channel/channelwebapiutils.h"
2020-12-07 19:32:43 +01:00
#include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h"
2020-11-30 01:30:18 +01:00
#include "maincore.h"
#include "vorlocalizerreport.h"
#include "vorlocalizerworker.h"
MESSAGE_CLASS_DEFINITION ( VorLocalizerWorker :: MsgConfigureVORLocalizerWorker , Message )
MESSAGE_CLASS_DEFINITION ( VorLocalizerWorker :: MsgRefreshChannels , Message )
class DSPDeviceSourceEngine ;
VorLocalizerWorker :: VorLocalizerWorker ( WebAPIAdapterInterface * webAPIAdapterInterface ) :
m_webAPIAdapterInterface ( webAPIAdapterInterface ),
2020-12-07 19:32:43 +01:00
m_msgQueueToFeature ( nullptr ),
m_availableChannels ( nullptr ),
2021-11-25 09:28:59 +00:00
m_updateTimer ( this ),
m_rrTimer ( this )
2020-11-30 01:30:18 +01:00
{
qDebug ( "VorLocalizerWorker::VorLocalizerWorker" );
connect ( & m_updateTimer , SIGNAL ( timeout ()), this , SLOT ( updateHardware ()));
}
VorLocalizerWorker ::~ VorLocalizerWorker ()
{
m_inputMessageQueue . clear ();
}
void VorLocalizerWorker :: reset ()
{
QMutexLocker mutexLocker ( & m_mutex );
m_inputMessageQueue . clear ();
}
2022-09-24 12:41:05 +02:00
void VorLocalizerWorker :: startWork ()
2020-11-30 01:30:18 +01:00
{
QMutexLocker mutexLocker ( & m_mutex );
connect ( & m_inputMessageQueue , SIGNAL ( messageEnqueued ()), this , SLOT ( handleInputMessages ()));
2020-12-07 19:32:43 +01:00
connect ( & m_rrTimer , SIGNAL ( timeout ()), this , SLOT ( rrNextTurn ()));
2021-11-25 09:28:59 +00:00
connect ( thread (), SIGNAL ( started ()), this , SLOT ( started ()));
connect ( thread (), SIGNAL ( finished ()), this , SLOT ( finished ()));
2020-11-30 01:30:18 +01:00
}
2021-11-25 09:28:59 +00:00
// startWork() is called from main thread. Timers/sockets need to be started on worker thread
void VorLocalizerWorker :: started ()
{
m_rrTimer . start ( m_settings . m_rrTime * 1000 );
disconnect ( thread (), SIGNAL ( started ()), this , SLOT ( started ()));
}
2022-05-04 08:27:25 +01:00
2020-11-30 01:30:18 +01:00
void VorLocalizerWorker :: stopWork ()
{
QMutexLocker mutexLocker ( & m_mutex );
2021-11-25 09:28:59 +00:00
disconnect ( & m_inputMessageQueue , SIGNAL ( messageEnqueued ()), this , SLOT ( handleInputMessages ()));
}
void VorLocalizerWorker :: finished ()
{
2020-12-07 19:32:43 +01:00
m_rrTimer . stop ();
disconnect ( & m_rrTimer , SIGNAL ( timeout ()), this , SLOT ( rrNextTurn ()));
2021-11-25 09:28:59 +00:00
disconnect ( thread (), SIGNAL ( finished ()), this , SLOT ( finished ()));
2020-11-30 01:30:18 +01:00
}
void VorLocalizerWorker :: handleInputMessages ()
{
Message * message ;
while (( message = m_inputMessageQueue . pop ()) != nullptr )
{
if ( handleMessage ( * message )) {
delete message ;
}
}
}
bool VorLocalizerWorker :: handleMessage ( const Message & cmd )
{
if ( MsgConfigureVORLocalizerWorker :: match ( cmd ))
{
QMutexLocker mutexLocker ( & m_mutex );
MsgConfigureVORLocalizerWorker & cfg = ( MsgConfigureVORLocalizerWorker & ) cmd ;
qDebug () << "VorLocalizerWorker::handleMessage: MsgConfigureVORLocalizerWorker" ;
2022-11-30 22:00:26 +01:00
applySettings ( cfg . getSettings (), cfg . getSettingsKeys (), cfg . getForce ());
2020-11-30 01:30:18 +01:00
return true ;
}
else if ( MsgRefreshChannels :: match ( cmd ))
{
qDebug () << "VorLocalizerWorker::handleMessage: MsgRefreshChannels" ;
updateChannels ();
2020-12-07 19:32:43 +01:00
2020-11-30 01:30:18 +01:00
return true ;
}
else
{
return false ;
}
}
2022-11-30 22:00:26 +01:00
void VorLocalizerWorker :: applySettings ( const VORLocalizerSettings & settings , const QList < QString >& settingsKeys , bool force )
2020-11-30 01:30:18 +01:00
{
2022-11-30 22:00:26 +01:00
qDebug () << "VorLocalizerWorker::applySettings:" << settings . getDebugString ( settingsKeys , force ) << " force: " << force ;
2020-11-30 01:30:18 +01:00
// Remove sub-channels no longer needed
for ( int i = 0 ; i < m_vorChannels . size (); i ++ )
{
if ( ! settings . m_subChannelSettings . contains ( m_vorChannels [ i ]. m_subChannelId ))
{
qDebug () << "VorLocalizerWorker::applySettings: Removing sink " << m_vorChannels [ i ]. m_subChannelId ;
removeVORChannel ( m_vorChannels [ i ]. m_subChannelId );
}
}
// Add new sub channels
2020-12-07 19:32:43 +01:00
QHash < int , VORLocalizerSubChannelSettings >:: const_iterator itr = settings . m_subChannelSettings . begin ();
2020-11-30 01:30:18 +01:00
while ( itr != settings . m_subChannelSettings . end ())
{
2020-12-07 19:32:43 +01:00
const VORLocalizerSubChannelSettings & subChannelSettings = itr . value ();
qDebug () << "VorLocalizerWorker::applySettings: subchannel " << subChannelSettings . m_id ;
2020-11-30 01:30:18 +01:00
int j = 0 ;
for (; j < m_vorChannels . size (); j ++ )
{
2020-12-07 19:32:43 +01:00
if ( subChannelSettings . m_id == m_vorChannels [ j ]. m_subChannelId )
{
qDebug () << "VorLocalizerWorker::applySettings: subchannel "
<< subChannelSettings . m_id
<< "already present" ;
2020-11-30 01:30:18 +01:00
break ;
2020-12-07 19:32:43 +01:00
}
2020-11-30 01:30:18 +01:00
}
if ( j == m_vorChannels . size ())
{
// Add a sub-channel sink
2020-12-07 19:32:43 +01:00
qDebug () << "VorLocalizerWorker::applySettings: Adding subchannel " << subChannelSettings . m_id ;
2020-11-30 01:30:18 +01:00
addVORChannel ( subChannelSettings );
}
++ itr ;
}
2020-12-07 19:32:43 +01:00
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 );
}
}
}
2022-11-30 22:00:26 +01:00
if ( settingsKeys . contains ( "rrTime" ) || force ) {
2020-12-07 19:32:43 +01:00
m_rrTimer . start ( settings . m_rrTime * 1000 );
}
2022-11-30 22:00:26 +01:00
if ( force ) {
m_settings = settings ;
} else {
m_settings . applySettings ( settingsKeys , settings );
}
2020-11-30 01:30:18 +01:00
}
void VorLocalizerWorker :: updateHardware ()
{
SWGSDRangel :: SWGSuccessResponse response ;
SWGSDRangel :: SWGErrorResponse error ;
m_updateTimer . stop ();
m_mutex . unlock ();
}
2022-05-04 08:27:25 +01:00
quint64 VorLocalizerWorker :: getDeviceCenterFrequency ( int deviceIndex )
{
std :: vector < DeviceSet *> deviceSets = MainCore :: instance () -> getDeviceSets ();
2022-05-08 19:33:10 +02:00
if ( deviceIndex < ( int ) deviceSets . size ())
2022-05-04 08:27:25 +01:00
{
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 ();
2022-05-08 19:33:10 +02:00
if ( deviceIndex < ( int ) deviceSets . size ())
2022-05-04 08:27:25 +01:00
{
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 );
}
2020-11-30 01:30:18 +01:00
void VorLocalizerWorker :: removeVORChannel ( int navId )
{
2020-12-07 19:32:43 +01:00
qDebug ( "VorLocalizerWorker::removeVORChannel: %d" , navId );
2020-11-30 01:30:18 +01:00
for ( int i = 0 ; i < m_vorChannels . size (); i ++ )
{
if ( m_vorChannels [ i ]. m_subChannelId == navId )
{
m_vorChannels . removeAt ( i );
break ;
}
}
2020-12-07 19:32:43 +01:00
updateChannels ();
2020-11-30 01:30:18 +01:00
}
2020-12-07 19:32:43 +01:00
void VorLocalizerWorker :: addVORChannel ( const VORLocalizerSubChannelSettings & subChannelSettings )
2020-11-30 01:30:18 +01:00
{
2020-12-07 19:32:43 +01:00
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
};
2020-11-30 01:30:18 +01:00
m_vorChannels . push_back ( vorChannel );
2020-12-07 19:32:43 +01:00
updateChannels ();
2020-11-30 01:30:18 +01:00
}
void VorLocalizerWorker :: updateChannels ()
{
2020-12-07 19:32:43 +01:00
qDebug () << "VorLocalizerWorker::updateChannels: "
<< "#VORs:" << m_vorChannels . size ()
<< "#Chans:" << m_availableChannels -> size ();
2020-11-30 01:30:18 +01:00
2020-12-07 19:32:43 +01:00
if (( m_vorChannels . size () == 0 ) || ( m_availableChannels -> size () == 0 )) {
return ;
}
2020-11-30 01:30:18 +01:00
2020-12-07 19:32:43 +01:00
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 )
2020-11-30 01:30:18 +01:00
{
2020-12-07 19:32:43 +01:00
unsigned int nbChannels = unallocatedVORs . size () < ( int ) deviceChannel . m_channels . size () ?
unallocatedVORs . size () :
deviceChannel . m_channels . size ();
std :: vector < VORRange > vorRanges ;
2020-11-30 01:30:18 +01:00
2020-12-07 19:32:43 +01:00
while ( nbChannels != 0 )
2020-11-30 01:30:18 +01:00
{
2020-12-07 19:32:43 +01:00
getVORRanges ( unallocatedVORs , nbChannels , vorRanges );
filterVORRanges ( vorRanges , deviceChannel . m_bandwidth );
2020-11-30 01:30:18 +01:00
2020-12-07 19:32:43 +01:00
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 ;
2022-05-04 08:27:25 +01:00
int devFreq ;
if ( turnPlan . m_fixedCenterFrequency ) {
devFreq = getDeviceCenterFrequency ( turnPlan . m_device . m_deviceIndex );
} else {
devFreq = ( fMin + fMax ) / 2 ;
}
2020-12-07 19:32:43 +01:00
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 ())
2020-11-30 01:30:18 +01:00
{
2020-12-07 19:32:43 +01:00
if ( it -> m_subChannelId == vorChannel . m_subChannelId ) {
it = unallocatedVORs . erase ( it );
} else {
++ it ;
}
2020-11-30 01:30:18 +01:00
}
2020-12-07 19:32:43 +01:00
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 ]));
2020-11-30 01:30:18 +01:00
}
2020-12-07 19:32:43 +01:00
vorLists . push_back ( vorList );
}
for ( auto vorList : vorLists )
{
RRTurnPlan turnPlan ( deviceChannel );
int fMin = vorList . front (). m_frequency ;
int fMax = vorList . back (). m_frequency ;
2022-05-04 08:27:25 +01:00
int devFreq ;
if ( turnPlan . m_fixedCenterFrequency ) {
devFreq = getDeviceCenterFrequency ( turnPlan . m_device . m_deviceIndex );
} else {
devFreq = ( fMin + fMax ) / 2 ;
}
2020-12-07 19:32:43 +01:00
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 );
2020-11-30 01:30:18 +01:00
}
}
2020-12-07 19:32:43 +01:00
for ( auto rrPlans : m_rrPlans )
2020-11-30 01:30:18 +01:00
{
2020-12-07 19:32:43 +01:00
qDebug () << "VorLocalizerWorker::updateChannels: RR plans for one device" ;
2020-11-30 01:30:18 +01:00
2020-12-07 19:32:43 +01:00
for ( auto rrPlan : rrPlans )
2020-11-30 01:30:18 +01:00
{
2020-12-07 19:32:43 +01:00
qDebug () << "VorLocalizerWorker::updateChannels: RR plan: "
<< "device:" << rrPlan . m_device . m_deviceIndex
<< "frequency:" << rrPlan . m_device . m_frequency ;
for ( auto rrChannel : rrPlan . m_channels )
{
2022-05-02 01:10:14 +02:00
qDebug ( "VorLocalizerWorker::updateChannels: RR channel: %p index: %d shift: %d navId: %d" ,
rrChannel . m_channelAPI , rrChannel . m_channelIndex , rrChannel . m_frequencyShift , rrChannel . m_navId );
2020-12-07 19:32:43 +01:00
}
2020-11-30 01:30:18 +01:00
}
2020-12-07 19:32:43 +01:00
}
m_rrTurnCounters . resize ( deviceCount );
std :: fill ( m_rrTurnCounters . begin (), m_rrTurnCounters . end (), 0 );
rrNextTurn ();
}
void VorLocalizerWorker :: setChannelShift ( int deviceIndex , int channelIndex , double targetOffset , int vorNavId )
{
SWGSDRangel :: SWGChannelSettings channelSettingsResponse ;
SWGSDRangel :: SWGErrorResponse errorResponse ;
int httpRC ;
2024-07-10 22:59:13 +02:00
// Get channel settings containing inputFrequencyOffset, so we can patch them
2020-12-07 19:32:43 +01:00
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 ;
2024-07-10 22:59:13 +02:00
// Get channel settings containing inputFrequencyOffset, so we can patch them
2020-12-07 19:32:43 +01:00
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 ();
2026-08-01 19:16:31 -04:00
unsigned int nbChannelsB = b . m_channels . size ();
2020-12-07 19:32:43 +01:00
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 ;
2022-05-04 08:27:25 +01:00
devicesChannelsMap [ itr -> m_deviceSetIndex ]. m_bandwidth = getDeviceSampleRate ( itr -> m_deviceSetIndex ); // Get b/w of device, not channel, as the latter may be decimated
2020-12-07 19:32:43 +01:00
devicesChannelsMap [ itr -> m_deviceSetIndex ]. m_channels . push_back ( RRChannel { itr -> m_channelAPI , itr -> m_channelIndex , 0 , - 1 });
}
2022-05-04 08:27:25 +01:00
QMap < int , RRTurnPlan >:: iterator itm = devicesChannelsMap . begin ();
2020-12-07 19:32:43 +01:00
devicesChannels . clear ();
2022-05-04 08:27:25 +01:00
for (; itm != devicesChannelsMap . end (); ++ itm )
{
itm -> m_fixedCenterFrequency = hasCenterFrequencySetting ( itm -> m_device . m_deviceIndex );
2020-12-07 19:32:43 +01:00
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 ;
2022-05-04 08:27:25 +01:00
2020-12-07 19:32:43 +01:00
qDebug () << "VorLocalizerWorker::rrNextTurn: "
<< "turn:" << turnCount
<< "device:" << deviceIndex
<< "frequency:" << deviceFrequency - m_settings . m_centerShift ;
2022-05-04 08:27:25 +01:00
if ( ! rrPlan [ turnCount ]. m_fixedCenterFrequency ) {
ChannelWebAPIUtils :: setCenterFrequency ( deviceIndex , deviceFrequency );
}
2020-12-07 19:32:43 +01:00
for ( auto channel : rrPlan [ turnCount ]. m_channels )
{
2022-05-04 08:27:25 +01:00
int shift = channel . m_frequencyShift ;
if ( ! rrPlan [ turnCount ]. m_fixedCenterFrequency ) {
shift += m_settings . m_centerShift ;
}
2020-12-07 19:32:43 +01:00
qDebug () << "VorLocalizerWorker::rrNextTurn: "
<< "device:" << deviceIndex
<< "channel:" << channel . m_channelIndex
2022-05-04 08:27:25 +01:00
<< "shift:" << shift
2020-12-07 19:32:43 +01:00
<< "navId:" << channel . m_navId ;
setChannelShift (
deviceIndex ,
channel . m_channelIndex ,
2022-05-04 08:27:25 +01:00
shift ,
2020-12-07 19:32:43 +01:00
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 ++ ;
}
2020-11-30 01:30:18 +01:00
2020-12-07 19:32:43 +01:00
if ( m_msgQueueToFeature ) {
m_msgQueueToFeature -> push ( msg );
2020-11-30 01:30:18 +01:00
}
}