diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index eb8d07da2..ff9a4a9ad 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -3100,7 +3100,7 @@ void ADSBDemodGUI::speechNotification(Aircraft *aircraft, const QString &speech) void ADSBDemodGUI::commandNotification(Aircraft *aircraft, const QString &command) { QString commandLine = subAircraftString(aircraft, command); - QStringList allArgs = commandLine.split(" "); + QStringList allArgs = QProcess::splitCommand(commandLine); if (allArgs.size() > 0) { diff --git a/plugins/feature/satellitetracker/readme.md b/plugins/feature/satellitetracker/readme.md index 238fbc065..ee5dca024 100644 --- a/plugins/feature/satellitetracker/readme.md +++ b/plugins/feature/satellitetracker/readme.md @@ -53,8 +53,8 @@ To perform an action on an SDRangel device set on AOS or LOS, press the "Add dev * Whether to stop acquisition on LOS. * Whether any file sinks in the preset should be started on AOS and stopped on LOS. This allows the baseband signal received from the satellite to be recorded to a file. * Whether to override the centre frequency in the preset. This allows a single preset to be used with multiple satellites. -* A command or script to execute on AOS. -* A command or script to execute on LOS. +* A command or script to execute on AOS. See (8) for list of subsitituions. +* A command or script to execute on LOS. See (8) for list of subsitituions. Multiple tabs can be added, to allow independent control of multiple device sets. To remove a tab, click the cross next to the device set name in the tab list. @@ -93,12 +93,14 @@ On the Settings tab, you can set: * A time window for which passes must start and end between, to be displayed or acted upon. For example, for day time passes, you could set "must start after" to 8:00 and "must end before" to 18:00. For night time passes, set "must start after" to 20:00 and "must end before" to 6:00. * The maximum azimuth angle in degrees supported by your rotator. 450 degree support is beneficial for passes that pass through 360/0 degrees, to avoid the rotator having to do a complete rotation mid pass. * The maximum elevation angle in degrees supported by your rotator. 180 degree support is beneficial for passes that pass through 360/0 degrees, to avoid the rotator having to do a complete rotation mid pass. -* A speech warning to be given on AOS. ${name} will be substituted with the name of the satellite, ${duration} the pass duration and ${elevation} the maximum elevation of the pass. -* A speech warning to be given on LOS. ${name} will be substituted with the name of the satellite. -* A command/script to be executed on AOS. This applies to all satellites. It is also possible to set a per-satellite command in the SDRangel Control dialog. +* A speech warning to be given on AOS. See below for a list of variable substitutions. +* A speech warning to be given on LOS. +* A command/script to be executed on AOS. This applies to all satellites. It is also possible to set a per-satellite command in the SDRangel Control dialog. See below for a list of variable substitions. * A command/script to be executed on LOS. This applies to all satellites. It is also possible to set a per-satellite command in the SDRangel Control dialog. * The Doppler correction period in seconds, which controls how frequently Doppler correction is applied. Which channels have Doppler correction applied is set on a per-channel basis in the SDRangel Control dialog. +For commands, scripts and speech, the following variables can be sustituted: ${aos}, ${los}, ${elevation}, ${aosAzimuth}, ${losAzimuth}, ${northToSouth}, ${latitude}, ${longitude}, ${altitude}, ${azimuth}, ${elevation}, ${range}, ${rangeRate}, ${speed} and ${period}. + ![Satellite tracker settings dialog](../../../doc/img/SatelliteTracker_plugin_settingsdialog2.png) On the TLEs tab, you can provide a list of URL from which satellite Two Line Element files can be downloaded from. diff --git a/plugins/feature/satellitetracker/satellitetrackergui.cpp b/plugins/feature/satellitetracker/satellitetrackergui.cpp index 5c98d9360..80d236f84 100644 --- a/plugins/feature/satellitetracker/satellitetrackergui.cpp +++ b/plugins/feature/satellitetracker/satellitetrackergui.cpp @@ -145,7 +145,7 @@ bool SatelliteTrackerGUI::handleMessage(const Message& message) else if (SatelliteTrackerReport::MsgReportAOS::match(message)) { SatelliteTrackerReport::MsgReportAOS& aosReport = (SatelliteTrackerReport::MsgReportAOS&) message; - aos(aosReport.getName(), aosReport.getDuration(), aosReport.getMaxElevation()); + aos(aosReport.getName(), aosReport.getSpeech()); return true; } else if (SatelliteTrackerReport::MsgReportTarget::match(message)) @@ -157,7 +157,7 @@ bool SatelliteTrackerGUI::handleMessage(const Message& message) else if (SatelliteTrackerReport::MsgReportLOS::match(message)) { SatelliteTrackerReport::MsgReportLOS& losReport = (SatelliteTrackerReport::MsgReportLOS&) message; - los(losReport.getName()); + los(losReport.getName(), losReport.getSpeech()); return true; } else if (SatelliteTracker::MsgSatData::match(message)) @@ -397,28 +397,20 @@ void SatelliteTrackerGUI::onMenuDialogCalled(const QPoint &p) resetContextMenuType(); } -void SatelliteTrackerGUI::aos(const QString& name, int duration, int maxElevation) +void SatelliteTrackerGUI::aos(const QString& name, const QString &speech) { // Call plotChart() to start the periodic updates with sat position in polar chart plotChart(); // Give speech notification of pass - QString speech = m_settings.m_aosSpeech.trimmed(); - if (!speech.isEmpty()) - { - speech = speech.replace("${name}", name); - speech = speech.replace("${duration}", QString::number(duration)); - speech = speech.replace("${elevation}", QString::number(maxElevation)); + if (!speech.isEmpty()) { m_speech->say(speech); } } -void SatelliteTrackerGUI::los(const QString& name) +void SatelliteTrackerGUI::los(const QString& name, const QString &speech) { // Give speech notification of end of pass - QString speech = m_settings.m_losSpeech.trimmed(); - if (!speech.isEmpty()) - { - speech = speech.replace("${name}", name); + if (!speech.isEmpty()) { m_speech->say(speech); } } diff --git a/plugins/feature/satellitetracker/satellitetrackergui.h b/plugins/feature/satellitetracker/satellitetrackergui.h index f5a058789..aa085debb 100644 --- a/plugins/feature/satellitetracker/satellitetrackergui.h +++ b/plugins/feature/satellitetracker/satellitetrackergui.h @@ -111,8 +111,8 @@ private: explicit SatelliteTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~SatelliteTrackerGUI(); - void aos(const QString& name, int duration, int maxElevation); - void los(const QString& name); + void aos(const QString& name, const QString &speech); + void los(const QString& name, const QString &speech); void blockApplySettings(bool block); void applySettings(bool force = false); diff --git a/plugins/feature/satellitetracker/satellitetrackerreport.h b/plugins/feature/satellitetracker/satellitetrackerreport.h index 8dfad0c78..8dcf4b19e 100644 --- a/plugins/feature/satellitetracker/satellitetrackerreport.h +++ b/plugins/feature/satellitetracker/satellitetrackerreport.h @@ -56,24 +56,21 @@ public: public: QString getName() const { return m_name; } - int getDuration() const { return m_duration; } - int getMaxElevation() const { return m_maxElevation; } + QString getSpeech() const { return m_speech; } - static MsgReportAOS* create(const QString& name, int duration, int maxElevation) + static MsgReportAOS* create(const QString& name, const QString &speech) { - return new MsgReportAOS(name, duration, maxElevation); + return new MsgReportAOS(name, speech); } private: QString m_name; - int m_duration; - int m_maxElevation; + QString m_speech; - MsgReportAOS(const QString& name, int duration, int maxElevation) : + MsgReportAOS(const QString& name, const QString &speech) : Message(), m_name(name), - m_duration(duration), - m_maxElevation(maxElevation) + m_speech(speech) { } }; @@ -84,18 +81,21 @@ public: public: QString getName() const { return m_name; } + QString getSpeech() const { return m_speech; } - static MsgReportLOS* create(const QString& name) + static MsgReportLOS* create(const QString& name, const QString &speech) { - return new MsgReportLOS(name); + return new MsgReportLOS(name, speech); } private: QString m_name; + QString m_speech; - MsgReportLOS(const QString& name) : + MsgReportLOS(const QString& name, const QString &speech) : Message(), - m_name(name) + m_name(name), + m_speech(speech) { } }; diff --git a/plugins/feature/satellitetracker/satellitetrackerworker.cpp b/plugins/feature/satellitetracker/satellitetrackerworker.cpp index d051d30b9..f8e66cc0f 100644 --- a/plugins/feature/satellitetracker/satellitetrackerworker.cpp +++ b/plugins/feature/satellitetracker/satellitetrackerworker.cpp @@ -545,11 +545,8 @@ void SatelliteTrackerWorker::aos(SatWorkerState *satWorkerState) // Indicate AOS to GUI if (getMessageQueueToGUI()) { - int durationMins = (int)round((satWorkerState->m_los.toSecsSinceEpoch() - satWorkerState->m_aos.toSecsSinceEpoch())/60.0); - int maxElevation = 0; - if (satWorkerState->m_satState.m_passes.size() > 0) - maxElevation = satWorkerState->m_satState.m_passes[0].m_maxElevation; - getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportAOS::create(satWorkerState->m_name, durationMins, maxElevation)); + QString speech = substituteVariables(m_settings.m_aosSpeech, satWorkerState->m_name); + getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportAOS::create(satWorkerState->m_name, speech)); } // Update target @@ -602,21 +599,59 @@ void SatelliteTrackerWorker::calculateRotation(SatWorkerState *satWorkerState) } } -void SatelliteTrackerWorker::applyDeviceAOSSettings(const QString& name) +QString SatelliteTrackerWorker::substituteVariables(const QString &textIn, const QString &satelliteName) { - // Execute global program/script - if (!m_settings.m_aosCommand.isEmpty()) + 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) { - qDebug() << "SatelliteTrackerWorker::aos: executing command: " << m_settings.m_aosCommand; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) - QStringList allArgs = m_settings.m_aosCommand.split(" ", Qt::SkipEmptyParts); -#else - QStringList allArgs = m_settings.m_aosCommand.split(" ", QString::SkipEmptyParts); -#endif + 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()) + { + // Replace variables + QString cmd = substituteVariables(command, satelliteName); + QStringList allArgs = QProcess::splitCommand(cmd); + qDebug() << "SatelliteTrackerWorker::executeCommand: Executing: " << allArgs; QString program = allArgs[0]; allArgs.pop_front(); QProcess::startDetached(program, allArgs); } +} + +void SatelliteTrackerWorker::applyDeviceAOSSettings(const QString& name) +{ + // Execute global program/script + if (!m_settings.m_aosCommand.isEmpty()) { + executeCommand(m_settings.m_aosCommand, name); + } // Update device set if (m_settings.m_deviceSettings.contains(name)) @@ -682,17 +717,8 @@ void SatelliteTrackerWorker::applyDeviceAOSSettings(const QString& name) } // Execute per satellite program/script - if (!devSettings->m_aosCommand.isEmpty()) - { - qDebug() << "SatelliteTrackerWorker::aos: executing command: " << devSettings->m_aosCommand; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) - QStringList allArgs = devSettings->m_aosCommand.split(" ", Qt::SkipEmptyParts); -#else - QStringList allArgs = devSettings->m_aosCommand.split(" ", QString::SkipEmptyParts); -#endif - QString program = allArgs[0]; - allArgs.pop_front(); - QProcess::startDetached(program, allArgs); + if (!devSettings->m_aosCommand.isEmpty()) { + executeCommand(devSettings->m_aosCommand, name); } } @@ -827,7 +853,10 @@ void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState) // Indicate LOS to GUI if (getMessageQueueToGUI()) - getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportLOS::create(satWorkerState->m_name)); + { + QString speech = substituteVariables(m_settings.m_losSpeech, satWorkerState->m_name); + getMessageQueueToGUI()->push(SatelliteTrackerReport::MsgReportLOS::create(satWorkerState->m_name, speech)); + } // Stop Doppler timer, and set interval to 0, so we don't restart it in start() satWorkerState->m_dopplerTimer.stop(); @@ -836,17 +865,8 @@ void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState) if (m_settings.m_target == satWorkerState->m_name) { // Execute program/script - if (!m_settings.m_losCommand.isEmpty()) - { - qDebug() << "SatelliteTrackerWorker::los: executing command: " << m_settings.m_losCommand; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) - QStringList allArgs = m_settings.m_losCommand.split(" ", Qt::SkipEmptyParts); -#else - QStringList allArgs = m_settings.m_losCommand.split(" ", QString::SkipEmptyParts); -#endif - QString program = allArgs[0]; - allArgs.pop_front(); - QProcess::startDetached(program, allArgs); + if (!m_settings.m_losCommand.isEmpty()) { + executeCommand(m_settings.m_losCommand, satWorkerState->m_name); } // Send LOS message to channels/features @@ -883,17 +903,8 @@ void SatelliteTrackerWorker::los(SatWorkerState *satWorkerState) for (int i = 0; i < m_deviceSettingsList->size(); i++) { SatelliteTrackerSettings::SatelliteDeviceSettings *devSettings = m_deviceSettingsList->at(i); - if (!devSettings->m_losCommand.isEmpty()) - { - qDebug() << "SatelliteTrackerWorker::los: executing command: " << devSettings->m_losCommand; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) - QStringList allArgs = devSettings->m_losCommand.split(" ", Qt::SkipEmptyParts); -#else - QStringList allArgs = devSettings->m_losCommand.split(" ", QString::SkipEmptyParts); -#endif - QString program = allArgs[0]; - allArgs.pop_front(); - QProcess::startDetached(program, allArgs); + if (!devSettings->m_losCommand.isEmpty()) { + executeCommand(devSettings->m_losCommand, satWorkerState->m_name); } } } diff --git a/plugins/feature/satellitetracker/satellitetrackerworker.h b/plugins/feature/satellitetracker/satellitetrackerworker.h index dfc3a4f04..b59c1a46e 100644 --- a/plugins/feature/satellitetracker/satellitetrackerworker.h +++ b/plugins/feature/satellitetracker/satellitetrackerworker.h @@ -141,6 +141,8 @@ private: void applyDeviceAOSSettings(const QString& name); void startStopSinks(bool start); void calculateRotation(SatWorkerState *satWorkerState); + QString substituteVariables(const QString &textIn, const QString &satelliteName); + void executeCommand(const QString &command, const QString &satelliteName); private slots: void stopWork();