2021-02-26 15:25:48 -05:00
///////////////////////////////////////////////////////////////////////////////////
2023-11-18 07:12:18 -05:00
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2022 Jiří Pinkava <jiri.pinkava@rossum.ai> //
// Copyright (C) 2023 Daniele Forsi <iu5hkx@gmail.com> //
2021-02-26 15:25:48 -05: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 <cmath>
# include <QDebug>
# include <QAbstractSocket>
# include <QTcpServer>
# include <QTcpSocket>
# include <QEventLoop>
# include <QTimer>
# include <QDateTime>
# include "SWGTargetAzimuthElevation.h"
# include "SWGMapItem.h"
# include "webapi/webapiadapterinterface.h"
# include "util/units.h"
# include "device/deviceset.h"
# include "device/deviceapi.h"
2023-05-20 02:57:19 -04:00
# include "channel/channelapi.h"
2021-02-26 15:25:48 -05:00
# include "channel/channelwebapiutils.h"
2021-04-07 16:23:02 -04:00
# include "feature/featurewebapiutils.h"
2021-02-26 15:25:48 -05:00
# include "maincore.h"
# include "satellitetracker.h"
# include "satellitetrackerworker.h"
# include "satellitetrackerreport.h"
# include "satellitetrackersgp4.h"
MESSAGE_CLASS_DEFINITION ( SatelliteTrackerWorker : : MsgConfigureSatelliteTrackerWorker , Message )
MESSAGE_CLASS_DEFINITION ( SatelliteTrackerReport : : MsgReportSat , Message )
MESSAGE_CLASS_DEFINITION ( SatelliteTrackerReport : : MsgReportAOS , Message )
MESSAGE_CLASS_DEFINITION ( SatelliteTrackerReport : : MsgReportLOS , Message )
MESSAGE_CLASS_DEFINITION ( SatelliteTrackerReport : : MsgReportTarget , Message )
SatelliteTrackerWorker : : SatelliteTrackerWorker ( SatelliteTracker * satelliteTracker , WebAPIAdapterInterface * webAPIAdapterInterface ) :
m_satelliteTracker ( satelliteTracker ) ,
m_webAPIAdapterInterface ( webAPIAdapterInterface ) ,
m_msgQueueToFeature ( nullptr ) ,
m_msgQueueToGUI ( nullptr ) ,
2021-11-25 04:28:59 -05:00
m_pollTimer ( this ) ,
2021-02-26 15:25:48 -05:00
m_recalculatePasses ( true ) ,
m_flipRotation ( false ) ,
m_extendedAzRotation ( false )
{
connect ( & m_pollTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( update ( ) ) ) ;
}
SatelliteTrackerWorker : : ~ SatelliteTrackerWorker ( )
{
2022-09-18 05:59:12 -04:00
qDebug ( ) < < " SatelliteTrackerWorker::~SatelliteTrackerWorker " ;
2022-09-20 16:14:36 -04:00
stopWork ( ) ;
2021-02-26 15:25:48 -05:00
m_inputMessageQueue . clear ( ) ;
2023-02-16 09:33:39 -05:00
// Remove satellites from Map
QHashIterator < QString , SatWorkerState * > itr ( m_workerState ) ;
while ( itr . hasNext ( ) )
{
itr . next ( ) ;
if ( m_settings . m_drawOnMap ) {
removeFromMap ( itr . key ( ) ) ;
}
}
qDeleteAll ( m_workerState ) ;
2021-02-26 15:25:48 -05:00
}
2022-09-18 11:45:25 -04:00
void SatelliteTrackerWorker : : startWork ( )
2021-02-26 15:25:48 -05:00
{
2022-09-18 05:59:12 -04:00
qDebug ( ) < < " SatelliteTrackerWorker::startWork " ;
2021-02-26 15:25:48 -05:00
QMutexLocker mutexLocker ( & m_mutex ) ;
connect ( & m_inputMessageQueue , SIGNAL ( messageEnqueued ( ) ) , this , SLOT ( handleInputMessages ( ) ) ) ;
2021-11-25 04:28:59 -05:00
m_recalculatePasses = true ;
2022-09-18 05:59:12 -04:00
m_pollTimer . start ( ( int ) round ( m_settings . m_updatePeriod * 1000.0 ) ) ;
2021-02-26 15:25:48 -05:00
// Resume doppler timers
QHashIterator < QString , SatWorkerState * > itr ( m_workerState ) ;
while ( itr . hasNext ( ) )
{
itr . next ( ) ;
SatWorkerState * satWorkerState = itr . value ( ) ;
if ( satWorkerState - > m_dopplerTimer . interval ( ) > 0 )
satWorkerState - > m_dopplerTimer . start ( ) ;
}
2022-09-18 05:59:12 -04:00
// Handle any messages already on the queue
handleInputMessages ( ) ;
2021-02-26 15:25:48 -05:00
}
void SatelliteTrackerWorker : : stopWork ( )
{
2022-09-18 05:59:12 -04:00
qDebug ( ) < < " SatelliteTrackerWorker::stopWork " ;
2021-02-26 15:25:48 -05:00
QMutexLocker mutexLocker ( & m_mutex ) ;
disconnect ( & m_inputMessageQueue , SIGNAL ( messageEnqueued ( ) ) , this , SLOT ( handleInputMessages ( ) ) ) ;
m_pollTimer . stop ( ) ;
// Stop doppler timers
QHashIterator < QString , SatWorkerState * > itr ( m_workerState ) ;
while ( itr . hasNext ( ) )
{
itr . next ( ) ;
itr . value ( ) - > m_dopplerTimer . stop ( ) ;
}
}
void SatelliteTrackerWorker : : handleInputMessages ( )
{
Message * message ;
while ( ( message = m_inputMessageQueue . pop ( ) ) ! = nullptr )
{
if ( handleMessage ( * message ) ) {
delete message ;
}
}
}
bool SatelliteTrackerWorker : : handleMessage ( const Message & message )
{
if ( MsgConfigureSatelliteTrackerWorker : : match ( message ) )
{
QMutexLocker mutexLocker ( & m_mutex ) ;
MsgConfigureSatelliteTrackerWorker & cfg = ( MsgConfigureSatelliteTrackerWorker & ) message ;
2022-11-28 15:52:06 -05:00
applySettings ( cfg . getSettings ( ) , cfg . getSettingsKeys ( ) , cfg . getForce ( ) ) ;
2021-02-26 15:25:48 -05:00
return true ;
}
else if ( SatelliteTracker : : MsgSatData : : match ( message ) )
{
SatelliteTracker : : MsgSatData & satData = ( SatelliteTracker : : MsgSatData & ) message ;
m_satellites = satData . getSatellites ( ) ;
m_recalculatePasses = true ;
return true ;
}
else
{
return false ;
}
}
2022-11-28 15:52:06 -05:00
void SatelliteTrackerWorker : : applySettings ( const SatelliteTrackerSettings & settings , const QList < QString > & settingsKeys , bool force )
2021-02-26 15:25:48 -05:00
{
2022-11-28 15:52:06 -05:00
qDebug ( ) < < " SatelliteTrackerWorker::applySettings: " < < settings . getDebugString ( settingsKeys , force ) < < " force: " < < force ;
if ( settingsKeys . contains ( " target " )
| | settingsKeys . contains ( " latitude " )
| | settingsKeys . contains ( " longitude " )
| | settingsKeys . contains ( " heightAboveSeaLevel " )
| | settingsKeys . contains ( " dateTime " )
| | settingsKeys . contains ( " utc " )
| | settingsKeys . contains ( " groundTrackPoints " )
| | settingsKeys . contains ( " minAOSElevation " )
| | settingsKeys . contains ( " minPassElevation " )
| | settingsKeys . contains ( " predictionPeriod " )
| | settingsKeys . contains ( " passStartTime " )
| | settingsKeys . contains ( " passFinishTime " )
2021-02-26 15:25:48 -05:00
| | ( ! m_settings . m_drawOnMap & & settings . m_drawOnMap )
| | force )
{
// Recalculate immediately
m_recalculatePasses = true ;
QTimer : : singleShot ( 1 , this , & SatelliteTrackerWorker : : update ) ;
m_pollTimer . start ( ( int ) round ( settings . m_updatePeriod * 1000.0 ) ) ;
}
2022-11-28 15:52:06 -05:00
else if ( settingsKeys . contains ( " updatePeriod " ) | | force )
2021-02-26 15:25:48 -05:00
{
m_pollTimer . start ( ( int ) round ( settings . m_updatePeriod * 1000.0 ) ) ;
}
if ( ! settings . m_drawOnMap & & m_settings . m_drawOnMap )
{
QHashIterator < QString , SatWorkerState * > itr ( m_workerState ) ;
while ( itr . hasNext ( ) )
{
itr . next ( ) ;
removeFromMap ( itr . key ( ) ) ;
}
}
// Remove satellites no longer needed
QMutableHashIterator < QString , SatWorkerState * > itr ( m_workerState ) ;
while ( itr . hasNext ( ) )
{
itr . next ( ) ;
if ( settings . m_satellites . indexOf ( itr . key ( ) ) = = - 1 )
2023-02-16 09:33:39 -05:00
{
if ( m_settings . m_drawOnMap ) {
removeFromMap ( itr . key ( ) ) ;
}
delete itr . value ( ) ;
2021-02-26 15:25:48 -05:00
itr . remove ( ) ;
2023-02-16 09:33:39 -05:00
}
2021-02-26 15:25:48 -05:00
}
// Add new satellites
for ( int i = 0 ; i < settings . m_satellites . size ( ) ; i + + )
{
if ( ! m_workerState . contains ( settings . m_satellites [ i ] ) )
{
SatWorkerState * satWorkerState = new SatWorkerState ( settings . m_satellites [ i ] ) ;
m_workerState . insert ( settings . m_satellites [ i ] , satWorkerState ) ;
connect ( & satWorkerState - > m_aosTimer , & QTimer : : timeout , [ this , satWorkerState ] ( ) {
aos ( satWorkerState ) ;
} ) ;
connect ( & satWorkerState - > m_losTimer , & QTimer : : timeout , [ this , satWorkerState ] ( ) {
los ( satWorkerState ) ;
} ) ;
m_recalculatePasses = true ;
}
}
2023-05-20 02:57:19 -04:00
if ( settingsKeys . contains ( " target " ) & & ( settings . m_target ! = m_settings . m_target ) )
{
if ( m_workerState . contains ( m_settings . m_target ) )
{
SatWorkerState * satWorkerState = m_workerState . value ( m_settings . m_target ) ;
disableDoppler ( satWorkerState ) ;
}
if ( m_workerState . contains ( settings . m_target ) )
{
SatWorkerState * satWorkerState = m_workerState . value ( settings . m_target ) ;
if ( satWorkerState - > hasAOS ( m_satelliteTracker - > currentDateTimeUtc ( ) ) ) {
enableDoppler ( satWorkerState ) ;
}
}
}
2022-11-28 15:52:06 -05:00
if ( force ) {
m_settings = settings ;
} else {
m_settings . applySettings ( settingsKeys , settings ) ;
}
2021-02-26 15:25:48 -05:00
}
void SatelliteTrackerWorker : : removeFromMap ( QString id )
{
2022-03-29 14:12:15 -04:00
QList < ObjectPipe * > mapMessagePipes ;
MainCore : : instance ( ) - > getMessagePipes ( ) . getMessagePipes ( m_satelliteTracker , " mapitems " , mapMessagePipes ) ;
if ( mapMessagePipes . size ( ) > 0 ) {
sendToMap ( mapMessagePipes , id , " " , " " , " " , 0.0f , 0.0 , 0.0 , 0.0 , 0.0 , nullptr , nullptr , nullptr , nullptr ) ;
}
2021-02-26 15:25:48 -05:00
}
2022-03-29 14:12:15 -04:00
void SatelliteTrackerWorker : : sendToMap (
const QList < ObjectPipe * > & mapMessagePipes ,
QString name ,
QString image ,
QString model ,
QString text ,
float labelOffset ,
double lat ,
double lon ,
double altitude ,
double rotation ,
QList < QGeoCoordinate * > * track ,
QList < QDateTime * > * trackDateTime ,
QList < QGeoCoordinate * > * predictedTrack ,
QList < QDateTime * > * predictedTrackDateTime
)
2021-02-26 15:25:48 -05:00
{
2022-03-29 14:12:15 -04:00
for ( const auto & pipe : mapMessagePipes )
2021-02-26 15:25:48 -05:00
{
2022-03-29 14:12:15 -04:00
MessageQueue * messageQueue = qobject_cast < MessageQueue * > ( pipe - > m_element ) ;
2021-02-26 15:25:48 -05:00
SWGSDRangel : : SWGMapItem * swgMapItem = new SWGSDRangel : : SWGMapItem ( ) ;
swgMapItem - > setName ( new QString ( name ) ) ;
swgMapItem - > setLatitude ( lat ) ;
swgMapItem - > setLongitude ( lon ) ;
swgMapItem - > setAltitude ( altitude ) ;
swgMapItem - > setImage ( new QString ( image ) ) ;
swgMapItem - > setImageRotation ( rotation ) ;
swgMapItem - > setText ( new QString ( text ) ) ;
2022-02-04 12:14:12 -05:00
swgMapItem - > setModel ( new QString ( model ) ) ;
swgMapItem - > setFixedPosition ( false ) ;
swgMapItem - > setOrientation ( 0 ) ;
swgMapItem - > setLabel ( new QString ( name ) ) ;
swgMapItem - > setLabelAltitudeOffset ( labelOffset ) ;
2021-02-26 15:25:48 -05:00
if ( track ! = nullptr )
{
QList < SWGSDRangel : : SWGMapCoordinate * > * mapTrack = new QList < SWGSDRangel : : SWGMapCoordinate * > ( ) ;
for ( int i = 0 ; i < track - > size ( ) ; i + + )
{
SWGSDRangel : : SWGMapCoordinate * p = new SWGSDRangel : : SWGMapCoordinate ( ) ;
QGeoCoordinate * c = track - > at ( i ) ;
p - > setLatitude ( c - > latitude ( ) ) ;
p - > setLongitude ( c - > longitude ( ) ) ;
p - > setAltitude ( c - > altitude ( ) ) ;
2022-02-04 12:14:12 -05:00
p - > setDateTime ( new QString ( trackDateTime - > at ( i ) - > toString ( Qt : : ISODate ) ) ) ;
2021-02-26 15:25:48 -05:00
mapTrack - > append ( p ) ;
}
swgMapItem - > setTrack ( mapTrack ) ;
}
if ( predictedTrack ! = nullptr )
{
QList < SWGSDRangel : : SWGMapCoordinate * > * mapTrack = new QList < SWGSDRangel : : SWGMapCoordinate * > ( ) ;
for ( int i = 0 ; i < predictedTrack - > size ( ) ; i + + )
{
SWGSDRangel : : SWGMapCoordinate * p = new SWGSDRangel : : SWGMapCoordinate ( ) ;
QGeoCoordinate * c = predictedTrack - > at ( i ) ;
p - > setLatitude ( c - > latitude ( ) ) ;
p - > setLongitude ( c - > longitude ( ) ) ;
p - > setAltitude ( c - > altitude ( ) ) ;
2022-02-04 12:14:12 -05:00
p - > setDateTime ( new QString ( predictedTrackDateTime - > at ( i ) - > toString ( Qt : : ISODate ) ) ) ;
2021-02-26 15:25:48 -05:00
mapTrack - > append ( p ) ;
}
swgMapItem - > setPredictedTrack ( mapTrack ) ;
}
MainCore : : MsgMapItem * msg = MainCore : : MsgMapItem : : create ( m_satelliteTracker , swgMapItem ) ;
2022-03-29 14:12:15 -04:00
messageQueue - > push ( msg ) ;
2021-02-26 15:25:48 -05:00
}
}
void SatelliteTrackerWorker : : update ( )
{
// Get date and time to calculate position at
QDateTime qdt ;
if ( m_settings . m_dateTime = = " " )
2022-02-04 12:14:12 -05:00
qdt = m_satelliteTracker - > currentDateTimeUtc ( ) ;
2021-02-26 15:25:48 -05:00
else if ( m_settings . m_utc )
qdt = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ;
else
qdt = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) . toUTC ( ) ;
2022-09-26 07:14:02 -04:00
bool timeReversed = m_lastUpdateDateTime > qdt ;
2021-02-26 15:25:48 -05:00
QHashIterator < QString , SatWorkerState * > itr ( m_workerState ) ;
while ( itr . hasNext ( ) )
{
itr . next ( ) ;
SatWorkerState * satWorkerState = itr . value ( ) ;
QString name = satWorkerState - > m_name ;
if ( m_satellites . contains ( name ) )
{
SatNogsSatellite * sat = m_satellites . value ( name ) ;
if ( sat - > m_tle ! = nullptr )
{
// Calculate position, AOS/LOS and other details for satellite
int noOfPasses ;
2022-09-18 05:59:12 -04:00
bool recalcAsPastLOS = ( satWorkerState - > m_satState . m_passes . size ( ) > 0 ) & & ( satWorkerState - > m_satState . m_passes [ 0 ] . m_los < qdt ) ;
2022-09-26 07:14:02 -04:00
if ( m_recalculatePasses | | recalcAsPastLOS | | timeReversed )
2021-02-26 15:25:48 -05:00
noOfPasses = ( name = = m_settings . m_target ) ? 99 : 1 ;
else
noOfPasses = 0 ;
getSatelliteState ( qdt , sat - > m_tle - > m_tle0 , sat - > m_tle - > m_tle1 , sat - > m_tle - > m_tle2 ,
m_settings . m_latitude , m_settings . m_longitude , m_settings . m_heightAboveSeaLevel / 1000.0 ,
m_settings . m_predictionPeriod , m_settings . m_minAOSElevation , m_settings . m_minPassElevation ,
m_settings . m_passStartTime , m_settings . m_passFinishTime , m_settings . m_utc ,
noOfPasses , m_settings . m_groundTrackPoints , & satWorkerState - > m_satState ) ;
2022-09-26 07:14:02 -04:00
// Update AOS/LOS
if ( satWorkerState - > m_satState . m_passes . size ( ) > 0 )
2021-02-26 15:25:48 -05:00
{
2022-09-26 07:14:02 -04:00
// Only use timers if using real time
if ( m_settings . m_dateTimeSelect = = SatelliteTrackerSettings : : NOW )
2021-02-26 15:25:48 -05:00
{
2022-09-26 07:14:02 -04:00
// Do we have a new pass?
if ( ( satWorkerState - > m_aos ! = satWorkerState - > m_satState . m_passes [ 0 ] . m_aos ) | | ( satWorkerState - > m_los ! = satWorkerState - > m_satState . m_passes [ 0 ] . m_los ) )
2021-02-26 15:25:48 -05:00
{
2022-09-26 07:14:02 -04:00
qDebug ( ) < < " SatelliteTrackerWorker: Current time: " < < qdt . toString ( Qt : : ISODateWithMs ) ;
qDebug ( ) < < " SatelliteTrackerWorker: New AOS: " < < name < < " new: " < < satWorkerState - > m_satState . m_passes [ 0 ] . m_aos < < " old: " < < satWorkerState - > m_aos ;
qDebug ( ) < < " SatelliteTrackerWorker: New LOS: " < < name < < " new: " < < satWorkerState - > m_satState . m_passes [ 0 ] . m_los < < " old: " < < satWorkerState - > m_los ;
satWorkerState - > m_aos = satWorkerState - > m_satState . m_passes [ 0 ] . m_aos ;
satWorkerState - > m_los = satWorkerState - > m_satState . m_passes [ 0 ] . m_los ;
satWorkerState - > m_hasSignalledAOS = false ;
if ( satWorkerState - > m_aos . isValid ( ) )
2021-02-26 15:25:48 -05:00
{
2022-09-26 07:14:02 -04:00
if ( satWorkerState - > m_aos > qdt )
{
satWorkerState - > m_aosTimer . setInterval ( satWorkerState - > m_aos . toMSecsSinceEpoch ( ) - qdt . toMSecsSinceEpoch ( ) ) ;
satWorkerState - > m_aosTimer . setSingleShot ( true ) ;
satWorkerState - > m_aosTimer . start ( ) ;
}
else if ( qdt < satWorkerState - > m_los )
aos ( satWorkerState ) ;
if ( satWorkerState - > m_los . isValid ( ) & & ( m_settings . m_target = = satWorkerState - > m_name ) )
calculateRotation ( satWorkerState ) ;
2021-02-26 15:25:48 -05:00
}
2022-09-26 07:14:02 -04:00
if ( satWorkerState - > m_los . isValid ( ) & & ( satWorkerState - > m_los > qdt ) )
2021-02-26 15:25:48 -05:00
{
2022-09-26 07:14:02 -04:00
if ( satWorkerState - > m_losTimer . isActive ( ) ) {
qDebug ( ) < < " SatelliteTrackerWorker::update m_losTimer.remainingTime: " < < satWorkerState - > m_losTimer . remainingTime ( ) ;
}
2024-07-10 16:59:13 -04:00
// We can detect a new AOS for a satellite, a little bit before the LOS has occurred
2022-09-26 07:14:02 -04:00
// Allow for 5s here (1s doesn't appear to be enough in some cases)
if ( satWorkerState - > m_losTimer . isActive ( ) & & ( satWorkerState - > m_losTimer . remainingTime ( ) < = 5000 ) )
{
satWorkerState - > m_losTimer . stop ( ) ;
// LOS hasn't been called yet - do so, before we reset timer
los ( satWorkerState ) ;
}
qDebug ( ) < < " SatelliteTrackerWorker:: Interval to LOS " < < ( satWorkerState - > m_los . toMSecsSinceEpoch ( ) - qdt . toMSecsSinceEpoch ( ) ) ;
satWorkerState - > m_losTimer . setInterval ( satWorkerState - > m_los . toMSecsSinceEpoch ( ) - qdt . toMSecsSinceEpoch ( ) ) ;
satWorkerState - > m_losTimer . setSingleShot ( true ) ;
satWorkerState - > m_losTimer . start ( ) ;
2021-02-26 15:25:48 -05:00
}
2022-09-26 07:14:02 -04:00
}
}
else
{
// Do we need to signal LOS?
if ( satWorkerState - > m_hasSignalledAOS & & ! satWorkerState - > hasAOS ( qdt ) )
{
los ( satWorkerState ) ;
satWorkerState - > m_hasSignalledAOS = false ;
}
// Do we have a new pass?
if ( ( satWorkerState - > m_aos ! = satWorkerState - > m_satState . m_passes [ 0 ] . m_aos ) | | ( satWorkerState - > m_los ! = satWorkerState - > m_satState . m_passes [ 0 ] . m_los ) )
{
satWorkerState - > m_aos = satWorkerState - > m_satState . m_passes [ 0 ] . m_aos ;
satWorkerState - > m_los = satWorkerState - > m_satState . m_passes [ 0 ] . m_los ;
satWorkerState - > m_hasSignalledAOS = false ;
}
// Check if we need to signal AOS
if ( ! satWorkerState - > m_hasSignalledAOS & & satWorkerState - > m_aos . isValid ( ) & & satWorkerState - > hasAOS ( qdt ) ) {
aos ( satWorkerState ) ;
2021-02-26 15:25:48 -05:00
}
}
}
else
{
satWorkerState - > m_aos = QDateTime ( ) ;
satWorkerState - > m_los = QDateTime ( ) ;
satWorkerState - > m_aosTimer . stop ( ) ;
satWorkerState - > m_losTimer . stop ( ) ;
}
// Send Az/El of target to Rotator Controllers, if elevation above horizon
if ( ( name = = m_settings . m_target ) & & ( satWorkerState - > m_satState . m_elevation > = 0 ) )
{
2023-05-20 02:57:19 -04:00
double azimuth = satWorkerState - > m_satState . m_azimuth + m_settings . m_azimuthOffset ;
double elevation = satWorkerState - > m_satState . m_elevation + m_settings . m_elevationOffset ;
2021-02-26 15:25:48 -05:00
if ( m_extendedAzRotation )
{
if ( azimuth < 180.0 )
azimuth + = 360.0 ;
}
else if ( m_flipRotation )
{
azimuth = std : : fmod ( azimuth + 180.0 , 360.0 ) ;
elevation = 180.0 - elevation ;
}
2022-03-28 14:12:25 -04:00
QList < ObjectPipe * > rotatorPipes ;
MainCore : : instance ( ) - > getMessagePipes ( ) . getMessagePipes ( m_satelliteTracker , " target " , rotatorPipes ) ;
for ( const auto & pipe : rotatorPipes )
{
MessageQueue * messageQueue = qobject_cast < MessageQueue * > ( pipe - > m_element ) ;
SWGSDRangel : : SWGTargetAzimuthElevation * swgTarget = new SWGSDRangel : : SWGTargetAzimuthElevation ( ) ;
swgTarget - > setName ( new QString ( m_settings . m_target ) ) ;
swgTarget - > setAzimuth ( azimuth ) ;
swgTarget - > setElevation ( elevation ) ;
messageQueue - > push ( MainCore : : MsgTargetAzimuthElevation : : create ( m_satelliteTracker , swgTarget ) ) ;
2021-02-26 15:25:48 -05:00
}
}
// Send to Map
if ( m_settings . m_drawOnMap )
{
2022-03-29 14:12:15 -04:00
QList < ObjectPipe * > mapMessagePipes ;
MainCore : : instance ( ) - > getMessagePipes ( ) . getMessagePipes ( m_satelliteTracker , " mapitems " , mapMessagePipes ) ;
if ( mapMessagePipes . size ( ) > 0 )
2021-02-26 15:25:48 -05:00
{
2022-02-04 12:14:12 -05:00
const QStringList cubeSats ( { " AISAT-1 " , " FOX-1B " , " FOX-1C " , " FOX-1D " , " FOX-1E " , " FUNCUBE-1 " , " NO-84 " } ) ;
2021-02-26 15:25:48 -05:00
QString image ;
2022-02-04 12:14:12 -05:00
QString model ;
float labelOffset ;
2021-02-26 15:25:48 -05:00
if ( sat - > m_name = = " ISS " )
2022-02-04 12:14:12 -05:00
{
2021-02-26 15:25:48 -05:00
image = " qrc:///satellitetracker/satellitetracker/iss-32.png " ;
2022-02-04 12:14:12 -05:00
model = " iss.glb " ;
labelOffset = 15.0f ;
}
else if ( cubeSats . contains ( sat - > m_name ) )
{
image = " qrc:///satellitetracker/satellitetracker/cubesat-32.png " ;
model = " cubesat.glb " ;
labelOffset = 0.7f ;
}
2021-02-26 15:25:48 -05:00
else
2022-02-04 12:14:12 -05:00
{
2021-02-26 15:25:48 -05:00
image = " qrc:///satellitetracker/satellitetracker/satellite-32.png " ;
2022-02-04 12:14:12 -05:00
model = " satellite.glb " ;
labelOffset = 2.5f ;
}
2021-02-26 15:25:48 -05:00
QString text = QString ( " Name: %1 \n Altitude: %2 km \n Range: %3 km \n Range rate: %4 km/s \n Speed: %5 km/h \n Period: %6 mins " )
. arg ( sat - > m_name )
. arg ( ( int ) round ( satWorkerState - > m_satState . m_altitude ) )
. arg ( ( int ) round ( satWorkerState - > m_satState . m_range ) )
. arg ( satWorkerState - > m_satState . m_rangeRate , 0 , ' f ' , 1 )
. arg ( Units : : kmpsToIntegerKPH ( satWorkerState - > m_satState . m_speed ) )
. arg ( ( int ) round ( satWorkerState - > m_satState . m_period ) ) ;
if ( satWorkerState - > m_satState . m_passes . size ( ) > 0 )
{
2022-09-18 05:59:12 -04:00
if ( ( qdt > = satWorkerState - > m_satState . m_passes [ 0 ] . m_aos ) & & ( qdt < = satWorkerState - > m_satState . m_passes [ 0 ] . m_los ) )
2021-02-26 15:25:48 -05:00
text = text . append ( " \n Satellite is visible " ) ;
else
2022-09-18 05:59:12 -04:00
text = text . append ( " \n AOS in: %1 mins " ) . arg ( ( int ) round ( ( satWorkerState - > m_satState . m_passes [ 0 ] . m_aos . toSecsSinceEpoch ( ) - qdt . toSecsSinceEpoch ( ) ) / 60.0 ) ) ;
2021-04-07 16:23:02 -04:00
QString aosDateTime ;
QString losDateTime ;
if ( m_settings . m_utc )
{
2022-09-18 05:59:12 -04:00
aosDateTime = satWorkerState - > m_satState . m_passes [ 0 ] . m_aos . toString ( m_settings . m_dateFormat + " hh:mm " ) ;
losDateTime = satWorkerState - > m_satState . m_passes [ 0 ] . m_los . toString ( m_settings . m_dateFormat + " hh:mm " ) ;
2021-04-07 16:23:02 -04:00
}
else
{
2022-09-18 05:59:12 -04:00
aosDateTime = satWorkerState - > m_satState . m_passes [ 0 ] . m_aos . toLocalTime ( ) . toString ( m_settings . m_dateFormat + " hh:mm " ) ;
losDateTime = satWorkerState - > m_satState . m_passes [ 0 ] . m_los . toLocalTime ( ) . toString ( m_settings . m_dateFormat + " hh:mm " ) ;
2021-04-07 16:23:02 -04:00
}
2021-02-26 15:25:48 -05:00
text = QString ( " %1 \n AOS: %2 \n LOS: %3 \n Max El: %4%5 " )
. arg ( text )
2021-04-07 16:23:02 -04:00
. arg ( aosDateTime )
. arg ( losDateTime )
2022-09-18 05:59:12 -04:00
. arg ( ( int ) round ( satWorkerState - > m_satState . m_passes [ 0 ] . m_maxElevation ) )
2021-02-26 15:25:48 -05:00
. arg ( QChar ( 0xb0 ) ) ;
}
2022-03-29 14:12:15 -04:00
sendToMap (
mapMessagePipes ,
sat - > m_name ,
image ,
model ,
text ,
labelOffset ,
satWorkerState - > m_satState . m_latitude , satWorkerState - > m_satState . m_longitude ,
satWorkerState - > m_satState . m_altitude * 1000.0 , 0 ,
& satWorkerState - > m_satState . m_groundTrack , & satWorkerState - > m_satState . m_groundTrackDateTime ,
& satWorkerState - > m_satState . m_predictedGroundTrack , & satWorkerState - > m_satState . m_predictedGroundTrackDateTime
) ;
2021-02-26 15:25:48 -05:00
}
}
// Send to GUI
if ( getMessageQueueToGUI ( ) )
getMessageQueueToGUI ( ) - > push ( SatelliteTrackerReport : : MsgReportSat : : create ( new SatelliteState ( satWorkerState - > m_satState ) ) ) ;
2022-02-06 06:13:09 -05:00
// Sent to Feature for Web report
if ( m_msgQueueToFeature )
m_msgQueueToFeature - > push ( SatelliteTrackerReport : : MsgReportSat : : create ( new SatelliteState ( satWorkerState - > m_satState ) ) ) ;
2021-02-26 15:25:48 -05:00
}
else
qDebug ( ) < < " SatelliteTrackerWorker::update: No TLE for " < < sat - > m_name < < " . Can't compute position. " ;
}
}
2022-09-26 07:14:02 -04:00
m_lastUpdateDateTime = qdt ;
2021-02-26 15:25:48 -05:00
m_recalculatePasses = false ;
}
void SatelliteTrackerWorker : : aos ( SatWorkerState * satWorkerState )
{
qDebug ( ) < < " SatelliteTrackerWorker::aos " < < satWorkerState - > m_name ;
2022-09-26 07:14:02 -04:00
satWorkerState - > m_hasSignalledAOS = true ;
2021-02-26 15:25:48 -05:00
// Indicate AOS to GUI
if ( getMessageQueueToGUI ( ) )
{
2022-09-29 11:50:04 -04:00
QString speech = substituteVariables ( m_settings . m_aosSpeech , satWorkerState - > m_name ) ;
getMessageQueueToGUI ( ) - > push ( SatelliteTrackerReport : : MsgReportAOS : : create ( satWorkerState - > m_name , speech ) ) ;
2021-02-26 15:25:48 -05:00
}
// Update target
if ( m_settings . m_autoTarget & & ( satWorkerState - > m_name ! = m_settings . m_target ) )
{
// Only switch if higher priority (earlier in list) or other target not in AOS
SatWorkerState * targetSatWorkerState = m_workerState . value ( m_settings . m_target ) ;
int currentTargetIdx = m_settings . m_satellites . indexOf ( m_settings . m_target ) ;
int newTargetIdx = m_settings . m_satellites . indexOf ( satWorkerState - > m_name ) ;
2022-02-04 12:14:12 -05:00
if ( ( newTargetIdx < currentTargetIdx ) | | ! targetSatWorkerState - > hasAOS ( m_satelliteTracker - > currentDateTimeUtc ( ) ) )
2021-02-26 15:25:48 -05:00
{
// Stop doppler correction for current target
if ( m_workerState . contains ( m_settings . m_target ) )
2023-05-20 02:57:19 -04:00
disableDoppler ( m_workerState . value ( m_settings . m_target ) ) ;
2021-02-26 15:25:48 -05:00
qDebug ( ) < < " SatelliteTrackerWorker::aos - autoTarget setting " < < satWorkerState - > m_name ;
m_settings . m_target = satWorkerState - > m_name ;
// Update GUI with new target
if ( getMessageQueueToGUI ( ) )
getMessageQueueToGUI ( ) - > push ( SatelliteTrackerReport : : MsgReportTarget : : create ( satWorkerState - > m_name ) ) ;
}
}
// TODO: Detect if different device sets are used and support multiple sats simultaneously
if ( m_settings . m_target = = satWorkerState - > m_name )
applyDeviceAOSSettings ( satWorkerState - > m_name ) ;
}
// Determine if we need to flip rotator or use extended azimuth to avoid 360/0 discontinuity
void SatelliteTrackerWorker : : calculateRotation ( SatWorkerState * satWorkerState )
{
m_flipRotation = false ;
m_extendedAzRotation = false ;
if ( satWorkerState - > m_satState . m_passes . size ( ) > 0 )
{
SatNogsSatellite * sat = m_satellites . value ( satWorkerState - > m_name ) ;
bool passes0 = getPassesThrough0Deg ( sat - > m_tle - > m_tle0 , sat - > m_tle - > m_tle1 , sat - > m_tle - > m_tle2 ,
m_settings . m_latitude , m_settings . m_longitude , m_settings . m_heightAboveSeaLevel / 1000.0 ,
2022-09-18 05:59:12 -04:00
satWorkerState - > m_satState . m_passes [ 0 ] . m_aos , satWorkerState - > m_satState . m_passes [ 0 ] . m_los ) ;
2021-02-26 15:25:48 -05:00
if ( passes0 )
{
2022-09-18 05:59:12 -04:00
double aosAz = satWorkerState - > m_satState . m_passes [ 0 ] . m_aosAzimuth ;
double losAz = satWorkerState - > m_satState . m_passes [ 0 ] . m_losAzimuth ;
2021-02-26 15:25:48 -05:00
double minAz = std : : min ( aosAz , losAz ) ;
if ( ( m_settings . m_rotatorMaxAzimuth - 360.0 ) > minAz )
m_extendedAzRotation = true ;
else if ( m_settings . m_rotatorMaxElevation = = 180.0 )
m_flipRotation = true ;
}
}
}
2022-09-29 11:50:04 -04:00
QString SatelliteTrackerWorker : : substituteVariables ( const QString & textIn , const QString & satelliteName )
2021-02-26 15:25:48 -05:00
{
2022-09-29 11:50:04 -04:00
SatWorkerState * satWorkerState = m_workerState . value ( satelliteName ) ;
if ( ! satWorkerState ) {
return " " ;
}
int durationMins = ( int ) round ( ( satWorkerState - > m_los . toSecsSinceEpoch ( ) - satWorkerState - > m_aos . toSecsSinceEpoch ( ) ) / 60.0 ) ;
QString text = textIn ;
text = text . replace ( " ${name} " , satelliteName ) ;
text = text . replace ( " ${duration} " , QString : : number ( durationMins ) ) ;
if ( satWorkerState - > m_satState . m_passes . size ( ) > 0 )
{
text = text . replace ( " ${aos} " , satWorkerState - > m_satState . m_passes [ 0 ] . m_aos . toString ( ) ) ;
text = text . replace ( " ${los} " , satWorkerState - > m_satState . m_passes [ 0 ] . m_los . toString ( ) ) ;
text = text . replace ( " ${elevation} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_passes [ 0 ] . m_maxElevation ) ) ) ;
text = text . replace ( " ${aosAzimuth} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_passes [ 0 ] . m_aosAzimuth ) ) ) ;
text = text . replace ( " ${losAzimuth} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_passes [ 0 ] . m_losAzimuth ) ) ) ;
text = text . replace ( " ${northToSouth} " , QString : : number ( satWorkerState - > m_satState . m_passes [ 0 ] . m_northToSouth ) ) ;
text = text . replace ( " ${latitude} " , QString : : number ( satWorkerState - > m_satState . m_latitude ) ) ;
text = text . replace ( " ${longitude} " , QString : : number ( satWorkerState - > m_satState . m_longitude ) ) ;
text = text . replace ( " ${altitude} " , QString : : number ( satWorkerState - > m_satState . m_altitude ) ) ;
text = text . replace ( " ${azimuth} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_azimuth ) ) ) ;
text = text . replace ( " ${elevation} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_elevation ) ) ) ;
text = text . replace ( " ${range} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_range ) ) ) ;
text = text . replace ( " ${rangeRate} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_rangeRate ) ) ) ;
text = text . replace ( " ${speed} " , QString : : number ( std : : round ( satWorkerState - > m_satState . m_speed ) ) ) ;
text = text . replace ( " ${period} " , QString : : number ( satWorkerState - > m_satState . m_period ) ) ;
}
return text ;
}
void SatelliteTrackerWorker : : executeCommand ( const QString & command , const QString & satelliteName )
{
if ( ! command . isEmpty ( ) )
2021-02-26 15:25:48 -05:00
{
2024-09-17 04:47:45 -04:00
# if QT_CONFIG(process)
2022-09-29 11:50:04 -04:00
// Replace variables
QString cmd = substituteVariables ( command , satelliteName ) ;
QStringList allArgs = QProcess : : splitCommand ( cmd ) ;
qDebug ( ) < < " SatelliteTrackerWorker::executeCommand: Executing: " < < allArgs ;
2021-12-27 13:16:59 -05:00
QString program = allArgs [ 0 ] ;
allArgs . pop_front ( ) ;
QProcess : : startDetached ( program , allArgs ) ;
2024-09-17 04:47:45 -04:00
# else
qWarning ( ) < < " SatelliteTrackerWorker::executeCommand: QProcess not supported. Can't run: " < < command ;
# endif
2021-02-26 15:25:48 -05:00
}
2022-09-29 11:50:04 -04:00
}
void SatelliteTrackerWorker : : applyDeviceAOSSettings ( const QString & name )
{
// Execute global program/script
if ( ! m_settings . m_aosCommand . isEmpty ( ) ) {
executeCommand ( m_settings . m_aosCommand , name ) ;
}
2021-02-26 15:25:48 -05:00
// Update device set
if ( m_settings . m_deviceSettings . contains ( name ) )
{
QList < SatelliteTrackerSettings : : SatelliteDeviceSettings * > * m_deviceSettingsList = m_settings . m_deviceSettings . value ( name ) ;
MainCore * mainCore = MainCore : : instance ( ) ;
// Load presets
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
2021-10-03 06:12:39 -04:00
if ( ! devSettings - > m_presetGroup . isEmpty ( ) )
2021-02-26 15:25:48 -05:00
{
const MainSettings & mainSettings = mainCore - > getSettings ( ) ;
2021-10-03 06:12:39 -04:00
const std : : vector < DeviceSet * > & deviceSets = mainCore - > getDeviceSets ( ) ;
2021-02-26 15:25:48 -05:00
2021-10-12 07:17:57 -04:00
if ( devSettings - > m_deviceSetIndex < ( int ) deviceSets . size ( ) )
2021-02-26 15:25:48 -05:00
{
2021-10-03 06:12:39 -04:00
const DeviceSet * deviceSet = deviceSets [ devSettings - > m_deviceSetIndex ] ;
QString presetType ;
if ( deviceSet - > m_deviceSourceEngine ! = nullptr ) {
presetType = " R " ;
} else if ( deviceSet - > m_deviceSinkEngine ! = nullptr ) {
presetType = " T " ;
} else if ( deviceSet - > m_deviceMIMOEngine ! = nullptr ) {
presetType = " M " ;
}
const Preset * preset = mainSettings . getPreset ( devSettings - > m_presetGroup , devSettings - > m_presetFrequency , devSettings - > m_presetDescription , presetType ) ;
if ( preset ! = nullptr )
2021-02-26 15:25:48 -05:00
{
2021-10-03 06:12:39 -04:00
qDebug ( ) < < " SatelliteTrackerWorker::aos: Loading preset " < < preset - > getDescription ( ) < < " to device set at " < < devSettings - > m_deviceSetIndex ;
MainCore : : MsgLoadPreset * msg = MainCore : : MsgLoadPreset : : create ( preset , devSettings - > m_deviceSetIndex ) ;
2021-02-26 15:25:48 -05:00
mainCore - > getMainMessageQueue ( ) - > push ( msg ) ;
}
else
2021-10-03 06:12:39 -04:00
{
qWarning ( ) < < " SatelliteTrackerWorker::aos: Unable to get preset: " < < devSettings - > m_presetGroup < < " " < < devSettings - > m_presetFrequency < < " " < < devSettings - > m_presetDescription ;
}
2021-02-26 15:25:48 -05:00
}
else
2021-10-03 06:12:39 -04:00
{
qWarning ( ) < < " SatelliteTrackerWorker::aos: device set at " < < devSettings - > m_deviceSetIndex < < " does not exist " ;
}
2021-02-26 15:25:48 -05:00
}
}
// Wait a little bit for presets to load before performing other steps
2022-09-18 11:45:25 -04:00
QTimer : : singleShot ( 1000 , [ this , name , m_deviceSettingsList ] ( )
2021-02-26 15:25:48 -05:00
{
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
// Override frequency
if ( devSettings - > m_frequency ! = 0 )
{
qDebug ( ) < < " SatelliteTrackerWorker::aos: setting frequency to: " < < devSettings - > m_frequency ;
2021-10-03 06:12:39 -04:00
ChannelWebAPIUtils : : setCenterFrequency ( devSettings - > m_deviceSetIndex , devSettings - > m_frequency ) ;
2021-02-26 15:25:48 -05:00
}
// Execute per satellite program/script
2022-09-29 11:50:04 -04:00
if ( ! devSettings - > m_aosCommand . isEmpty ( ) ) {
executeCommand ( devSettings - > m_aosCommand , name ) ;
2021-02-26 15:25:48 -05:00
}
}
// Start acquisition - Need to use WebAPI, in order for GUI to correctly reflect being started
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
if ( devSettings - > m_startOnAOS )
{
2023-07-23 10:44:42 -04:00
qDebug ( ) < < " SatelliteTrackerWorker::aos: starting acquisition " ;
2021-10-03 06:12:39 -04:00
ChannelWebAPIUtils : : run ( devSettings - > m_deviceSetIndex ) ;
2021-02-26 15:25:48 -05:00
}
}
2021-04-07 16:23:02 -04:00
// Send AOS message to channels/features
2021-02-26 15:25:48 -05:00
SatWorkerState * satWorkerState = m_workerState . value ( name ) ;
2022-02-04 12:14:12 -05:00
SatNogsSatellite * sat = m_satellites . value ( satWorkerState - > m_name ) ;
// APT needs current time, for current position of satellite, not start of pass which may be in the past
// if the satellite was already visible when Sat Tracker was started
2022-09-18 05:59:12 -04:00
ChannelWebAPIUtils : : satelliteAOS ( name , satWorkerState - > m_satState . m_passes [ 0 ] . m_northToSouth ,
2022-02-04 12:14:12 -05:00
sat - > m_tle - > toString ( ) ,
m_satelliteTracker - > currentDateTimeUtc ( ) ) ;
2021-04-07 16:23:02 -04:00
FeatureWebAPIUtils : : satelliteAOS ( name , satWorkerState - > m_aos , satWorkerState - > m_los ) ;
2021-02-26 15:25:48 -05:00
// Start Doppler correction, if needed
2023-05-20 02:57:19 -04:00
enableDoppler ( satWorkerState ) ;
2021-03-08 17:10:43 -05:00
// Start file sinks (need a little delay to ensure sample rate message has been handled in filerecord)
2022-09-18 11:45:25 -04:00
QTimer : : singleShot ( 1000 , [ m_deviceSettingsList ] ( )
2021-03-08 17:10:43 -05:00
{
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
if ( devSettings - > m_startStopFileSink )
{
qDebug ( ) < < " SatelliteTrackerWorker::aos: starting file sinks " ;
2021-10-03 06:12:39 -04:00
ChannelWebAPIUtils : : startStopFileSinks ( devSettings - > m_deviceSetIndex , true ) ;
2021-03-08 17:10:43 -05:00
}
}
} ) ;
2021-02-26 15:25:48 -05:00
} ) ;
}
else
{
2021-04-07 16:23:02 -04:00
// Send AOS message to channels/features
2021-02-26 15:25:48 -05:00
SatWorkerState * satWorkerState = m_workerState . value ( name ) ;
2022-02-04 12:14:12 -05:00
SatNogsSatellite * sat = m_satellites . value ( satWorkerState - > m_name ) ;
2022-09-18 05:59:12 -04:00
ChannelWebAPIUtils : : satelliteAOS ( name , satWorkerState - > m_satState . m_passes [ 0 ] . m_northToSouth ,
2022-02-04 12:14:12 -05:00
sat - > m_tle - > toString ( ) ,
m_satelliteTracker - > currentDateTimeUtc ( ) ) ;
2021-04-07 16:23:02 -04:00
FeatureWebAPIUtils : : satelliteAOS ( name , satWorkerState - > m_aos , satWorkerState - > m_los ) ;
2021-02-26 15:25:48 -05:00
}
}
2023-05-20 02:57:19 -04:00
void SatelliteTrackerWorker : : enableDoppler ( SatWorkerState * satWorkerState )
{
QList < SatelliteTrackerSettings : : SatelliteDeviceSettings * > * m_deviceSettingsList = m_settings . m_deviceSettings . value ( satWorkerState - > m_name ) ;
2023-05-23 17:27:35 -04:00
if ( m_deviceSettingsList )
2023-05-20 02:57:19 -04:00
{
2023-05-23 17:27:35 -04:00
satWorkerState - > m_doppler . clear ( ) ;
bool requiresDoppler = false ;
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
2023-05-20 02:57:19 -04:00
{
2023-05-23 17:27:35 -04:00
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
if ( devSettings - > m_doppler . size ( ) > 0 )
{
requiresDoppler = true ;
for ( int j = 0 ; j < devSettings - > m_doppler . size ( ) ; j + + ) {
satWorkerState - > m_doppler . append ( 0 ) ;
}
2023-05-20 02:57:19 -04:00
}
}
2023-05-23 17:27:35 -04:00
if ( requiresDoppler )
{
qDebug ( ) < < " SatelliteTrackerWorker::applyDeviceAOSSettings: Enabling doppler for " < < satWorkerState - > m_name ;
satWorkerState - > m_dopplerTimer . setInterval ( m_settings . m_dopplerPeriod * 1000 ) ;
satWorkerState - > m_dopplerTimer . start ( ) ;
connect ( & satWorkerState - > m_dopplerTimer , & QTimer : : timeout , [ this , satWorkerState ] ( ) {
doppler ( satWorkerState ) ;
} ) ;
}
2023-05-20 02:57:19 -04:00
}
}
void SatelliteTrackerWorker : : disableDoppler ( SatWorkerState * satWorkerState )
{
// Stop Doppler timer, and set interval to 0, so we don't restart it in start()
satWorkerState - > m_dopplerTimer . stop ( ) ;
satWorkerState - > m_dopplerTimer . setInterval ( 0 ) ;
// Remove doppler correction from any channel
QList < SatelliteTrackerSettings : : SatelliteDeviceSettings * > * m_deviceSettingsList = m_settings . m_deviceSettings . value ( satWorkerState - > m_name ) ;
if ( m_deviceSettingsList )
{
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
if ( devSettings - > m_doppler . size ( ) > 0 )
{
for ( int j = 0 ; j < devSettings - > m_doppler . size ( ) ; j + + )
{
int offset ;
if ( ChannelWebAPIUtils : : getFrequencyOffset ( devSettings - > m_deviceSetIndex , devSettings - > m_doppler [ j ] , offset ) )
{
// Remove old doppler
offset + = satWorkerState - > m_doppler [ i ] ;
if ( ! ChannelWebAPIUtils : : setFrequencyOffset ( devSettings - > m_deviceSetIndex , devSettings - > m_doppler [ j ] , offset ) )
qDebug ( ) < < " SatelliteTrackerWorker::doppler: Failed to set frequency offset " ;
}
else
qDebug ( ) < < " SatelliteTrackerWorker::doppler: Failed to get frequency offset " ;
}
satWorkerState - > m_doppler [ i ] = 0 ;
}
}
}
}
2021-02-26 15:25:48 -05:00
void SatelliteTrackerWorker : : doppler ( SatWorkerState * satWorkerState )
{
qDebug ( ) < < " SatelliteTrackerWorker::doppler " < < satWorkerState - > m_name ;
QList < SatelliteTrackerSettings : : SatelliteDeviceSettings * > * m_deviceSettingsList = m_settings . m_deviceSettings . value ( satWorkerState - > m_name ) ;
2023-05-23 17:27:35 -04:00
if ( m_deviceSettingsList )
2021-02-26 15:25:48 -05:00
{
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
if ( devSettings - > m_doppler . size ( ) > 0 )
{
// Get center frequency for this device
double centerFrequency ;
2021-10-03 06:12:39 -04:00
if ( ChannelWebAPIUtils : : getCenterFrequency ( devSettings - > m_deviceSetIndex , centerFrequency ) )
2021-02-26 15:25:48 -05:00
{
// Calculate frequency delta due to Doppler
double c = 299792458.0 ;
double deltaF = centerFrequency * satWorkerState - > m_satState . m_rangeRate * 1000.0 / c ;
2023-05-20 02:57:19 -04:00
int doppler = ( int ) round ( deltaF ) ;
2021-02-26 15:25:48 -05:00
for ( int j = 0 ; j < devSettings - > m_doppler . size ( ) ; j + + )
{
2023-05-20 02:57:19 -04:00
int offset ;
if ( ChannelWebAPIUtils : : getFrequencyOffset ( devSettings - > m_deviceSetIndex , devSettings - > m_doppler [ j ] , offset ) )
{
// Apply doppler - For receive, we subtract, transmit we add
std : : vector < DeviceSet * > & deviceSets = MainCore : : instance ( ) - > getDeviceSets ( ) ;
ChannelAPI * channel = deviceSets [ devSettings - > m_deviceSetIndex ] - > getChannelAt ( j ) ;
int tx = false ;
if ( channel ) {
tx = channel - > getStreamType ( ) = = ChannelAPI : : StreamSingleSource ; // What if MIMO?
}
2021-02-26 15:25:48 -05:00
2023-05-20 02:57:19 -04:00
// Remove old doppler and apply new
int initOffset ;
if ( tx )
{
initOffset = offset - satWorkerState - > m_doppler [ i ] ;
offset = initOffset + doppler ;
}
else
{
initOffset = offset + satWorkerState - > m_doppler [ i ] ;
offset = initOffset - doppler ;
}
if ( ! ChannelWebAPIUtils : : setFrequencyOffset ( devSettings - > m_deviceSetIndex , devSettings - > m_doppler [ j ] , offset ) )
qDebug ( ) < < " SatelliteTrackerWorker::doppler: Failed to set frequency offset " ;
}
else
qDebug ( ) < < " SatelliteTrackerWorker::doppler: Failed to get frequency offset " ;
2021-02-26 15:25:48 -05:00
}
2023-05-20 02:57:19 -04:00
satWorkerState - > m_doppler [ i ] = doppler ;
2021-02-26 15:25:48 -05:00
}
else
2021-10-03 06:12:39 -04:00
qDebug ( ) < < " SatelliteTrackerWorker::doppler: couldn't get centre frequency for device at " < < devSettings - > m_deviceSetIndex ;
2021-02-26 15:25:48 -05:00
}
}
}
}
void SatelliteTrackerWorker : : los ( SatWorkerState * satWorkerState )
{
2022-02-04 12:14:12 -05:00
qDebug ( ) < < " SatelliteTrackerWorker::los " < < satWorkerState - > m_name < < " target: " < < m_settings . m_target ;
2021-02-26 15:25:48 -05:00
// Indicate LOS to GUI
if ( getMessageQueueToGUI ( ) )
2022-09-29 11:50:04 -04:00
{
QString speech = substituteVariables ( m_settings . m_losSpeech , satWorkerState - > m_name ) ;
getMessageQueueToGUI ( ) - > push ( SatelliteTrackerReport : : MsgReportLOS : : create ( satWorkerState - > m_name , speech ) ) ;
}
2021-02-26 15:25:48 -05:00
2023-05-20 02:57:19 -04:00
disableDoppler ( satWorkerState ) ;
2021-02-26 15:25:48 -05:00
if ( m_settings . m_target = = satWorkerState - > m_name )
{
// Execute program/script
2022-09-29 11:50:04 -04:00
if ( ! m_settings . m_losCommand . isEmpty ( ) ) {
executeCommand ( m_settings . m_losCommand , satWorkerState - > m_name ) ;
2021-02-26 15:25:48 -05:00
}
2022-02-04 12:14:12 -05:00
// Send LOS message to channels/features
ChannelWebAPIUtils : : satelliteLOS ( satWorkerState - > m_name ) ;
FeatureWebAPIUtils : : satelliteLOS ( satWorkerState - > m_name ) ;
2021-02-26 15:25:48 -05:00
if ( m_settings . m_deviceSettings . contains ( satWorkerState - > m_name ) )
{
QList < SatelliteTrackerSettings : : SatelliteDeviceSettings * > * m_deviceSettingsList = m_settings . m_deviceSettings . value ( satWorkerState - > m_name ) ;
// Stop file sinks
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
if ( devSettings - > m_startStopFileSink )
{
qDebug ( ) < < " SatelliteTrackerWorker::los: stopping file sinks " ;
2021-10-03 06:12:39 -04:00
ChannelWebAPIUtils : : startStopFileSinks ( devSettings - > m_deviceSetIndex , false ) ;
2021-02-26 15:25:48 -05:00
}
}
// Stop acquisition
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
2021-10-03 06:12:39 -04:00
if ( devSettings - > m_stopOnLOS ) {
ChannelWebAPIUtils : : stop ( devSettings - > m_deviceSetIndex ) ;
2021-02-26 15:25:48 -05:00
}
}
// Execute per satellite program/script
// Do after stopping acquisition, so files are closed by file sink
for ( int i = 0 ; i < m_deviceSettingsList - > size ( ) ; i + + )
{
SatelliteTrackerSettings : : SatelliteDeviceSettings * devSettings = m_deviceSettingsList - > at ( i ) ;
2022-09-29 11:50:04 -04:00
if ( ! devSettings - > m_losCommand . isEmpty ( ) ) {
executeCommand ( devSettings - > m_losCommand , satWorkerState - > m_name ) ;
2021-02-26 15:25:48 -05:00
}
}
}
}
// Is another lower-priority satellite with AOS available to switch to?
if ( m_settings . m_autoTarget )
{
for ( int i = m_settings . m_satellites . indexOf ( m_settings . m_target ) + 1 ; i < m_settings . m_satellites . size ( ) ; i + + )
{
if ( m_workerState . contains ( m_settings . m_satellites [ i ] ) )
{
SatWorkerState * newSatWorkerState = m_workerState . value ( m_settings . m_satellites [ i ] ) ;
2022-02-04 12:14:12 -05:00
if ( newSatWorkerState - > hasAOS ( m_satelliteTracker - > currentDateTimeUtc ( ) ) )
2021-02-26 15:25:48 -05:00
{
qDebug ( ) < < " SatelliteTrackerWorker::los - autoTarget setting " < < m_settings . m_satellites [ i ] ;
m_settings . m_target = m_settings . m_satellites [ i ] ;
// Update GUI with new target
if ( getMessageQueueToGUI ( ) )
getMessageQueueToGUI ( ) - > push ( SatelliteTrackerReport : : MsgReportTarget : : create ( m_settings . m_target ) ) ;
// Apply device settings
applyDeviceAOSSettings ( m_settings . m_target ) ;
break ;
}
}
}
}
m_recalculatePasses = true ;
}
2021-07-28 09:10:23 -04:00
2022-02-04 12:14:12 -05:00
bool SatWorkerState : : hasAOS ( const QDateTime & currentTime )
2021-07-28 09:10:23 -04:00
{
return ( m_aos < = currentTime ) & & ( m_los > currentTime ) ;
}