diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 598bde0b2..a646a4821 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -9,12 +9,16 @@ on: jobs: build_mac_x64: - runs-on: macos-12 + runs-on: macos-13 steps: - uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 + - name: Update brew + run: brew update + - name: Install brew packages + run: brew install nasm subversion - name: Install SDRplay API run: | wget https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.15.0.pkg @@ -40,7 +44,23 @@ jobs: - name: Build SDRangel on Mac run: | cd build - make -j4 package + make -j4 + - name: Create dmg + run: | + cd build + RETRIES=5 + COUNT=1 + set +e + while [ $COUNT -lt $RETRIES ]; do + make package + if [ $? -eq 0 ]; then + RETRIES=0 + break + fi + let COUNT=$COUNT+1 + done + shell: bash + continue-on-error: true - name: Get version id: get_version run: | @@ -99,7 +119,23 @@ jobs: - name: Build SDRangel on Mac run: | cd build - make -j3 package + make -j3 + - name: Create dmg + run: | + cd build + RETRIES=5 + COUNT=1 + set +e + while [ $COUNT -lt $RETRIES ]; do + make package + if [ $? -eq 0 ]; then + RETRIES=0 + break + fi + let COUNT=$COUNT+1 + done + shell: bash + continue-on-error: true - name: Get version id: get_version run: | diff --git a/CHANGELOG b/CHANGELOG index a451c89e1..684d21059 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +sdrangel (7.22.6-1) unstable; urgency=medium + + * See Github release + + -- Edouard Griffiths, F4EXB Sun, 02 Feb 2025 18:08:11 +0100 + sdrangel (7.22.5-1) unstable; urgency=medium * Windows: upload signed releases rather than unsigned releases to Github releases page. PR #2347 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7944dd8e0..9ab7abda1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # configure version set(sdrangel_VERSION_MAJOR "7") set(sdrangel_VERSION_MINOR "22") -set(sdrangel_VERSION_PATCH "5") +set(sdrangel_VERSION_PATCH "6") set(sdrangel_VERSION_SUFFIX "") # SDRAngel cmake options diff --git a/cmake/Modules/CompilerOptions.cmake b/cmake/Modules/CompilerOptions.cmake index 75b698171..64f84c72a 100644 --- a/cmake/Modules/CompilerOptions.cmake +++ b/cmake/Modules/CompilerOptions.cmake @@ -19,7 +19,11 @@ if(WIN32) endif() if(NOT MSVC) - add_compile_options(-Wall -Wextra -Wvla -Woverloaded-virtual -Wno-inconsistent-missing-override -ffast-math -fno-finite-math-only -ftree-vectorize) + add_compile_options(-Wall -Wextra -Wvla -ffast-math -fno-finite-math-only -ftree-vectorize) + add_compile_options($<$:-Woverloaded-virtual>) + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_compile_options(-Wno-inconsistent-missing-override) + endif() else() # Disable some warnings, so more useful warnings aren't hidden in the noise # 4996 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. diff --git a/debian/changelog b/debian/changelog index cbcb73a4d..f83d75ef6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +sdrangel (7.22.6-1) unstable; urgency=medium + + * See Github release + + -- Edouard Griffiths, F4EXB Sun, 02 Feb 2025 18:08:11 +0100 + sdrangel (7.22.5-1) unstable; urgency=medium * Windows: upload signed releases rather than unsigned releases to Github releases page. PR #2347 diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index d84f58523..33d5948c7 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -420,6 +420,7 @@ if (NOT FFMPEG_FOUND AND NOT USE_PRECOMPILED_LIBS) if (NOT X265_FOUND OR X265_EXTERNAL) ExternalProject_Add(x265 GIT_REPOSITORY https://bitbucket.org/multicoreware/x265_git.git + GIT_TAG 4.1 PREFIX "${EXTERNAL_BUILD_LIBRARIES}/x265" SOURCE_SUBDIR "source" CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX= diff --git a/gitdiff.sh b/gitdiff.sh index 6af69efba..e6deb2802 100755 --- a/gitdiff.sh +++ b/gitdiff.sh @@ -4,6 +4,7 @@ PLUGINS=$(git diff --name-only ${1}..${2} | grep plugins/ | cut -d'/' -f2,3 | so for plugin in $PLUGINS do FILE=$(find $BASEDIR/plugins/$plugin -name "*plugin.cpp") - sed -i -E "s/QStringLiteral\(\"7\.(.*)\"\)/QStringLiteral\(\"7\.22\.5\"\)/" $FILE + echo $FILE + sed -i -E "s/QStringLiteral\(\"7\.(.*)\"\)/QStringLiteral\(\"7\.22\.6\"\)/" $FILE done diff --git a/plugins/channelrx/demodadsb/adsbplugin.cpp b/plugins/channelrx/demodadsb/adsbplugin.cpp index 72650461c..b7b402315 100644 --- a/plugins/channelrx/demodadsb/adsbplugin.cpp +++ b/plugins/channelrx/demodadsb/adsbplugin.cpp @@ -30,7 +30,7 @@ const PluginDescriptor ADSBPlugin::m_pluginDescriptor = { ADSBDemod::m_channelId, QStringLiteral("ADS-B Demodulator"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channelrx/demoddsc/dscdemodplugin.cpp b/plugins/channelrx/demoddsc/dscdemodplugin.cpp index 673437909..e3134aa4c 100644 --- a/plugins/channelrx/demoddsc/dscdemodplugin.cpp +++ b/plugins/channelrx/demoddsc/dscdemodplugin.cpp @@ -33,7 +33,7 @@ const PluginDescriptor DSCDemodPlugin::m_pluginDescriptor = { DSCDemod::m_channelId, QStringLiteral("DSC Demodulator"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channelrx/filesink/filesinkgui.ui b/plugins/channelrx/filesink/filesinkgui.ui index e9fc5b051..31812990c 100644 --- a/plugins/channelrx/filesink/filesinkgui.ui +++ b/plugins/channelrx/filesink/filesinkgui.ui @@ -107,7 +107,7 @@ PointingHandCursor - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus Demod shift frequency from center in Hz @@ -124,7 +124,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -186,7 +186,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -211,7 +211,7 @@ 0000k - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -230,7 +230,7 @@ #000 - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -265,7 +265,7 @@ 999.99M - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -298,7 +298,7 @@ 1 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -317,14 +317,14 @@ 000 - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::Vertical + Qt::Orientation::Vertical @@ -368,6 +368,12 @@ + + + 30 + 0 + + Spectrum squelch level (dB) @@ -397,6 +403,12 @@ + + + 16 + 0 + + Squelched recoding pre-recording time (s) @@ -426,6 +438,12 @@ + + + 16 + 0 + + Squelched recording post-recording time (s) @@ -506,7 +524,7 @@ ... - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter diff --git a/plugins/channelrx/filesink/filesinkplugin.cpp b/plugins/channelrx/filesink/filesinkplugin.cpp index 8c50fef86..0966cd9d1 100644 --- a/plugins/channelrx/filesink/filesinkplugin.cpp +++ b/plugins/channelrx/filesink/filesinkplugin.cpp @@ -33,7 +33,7 @@ const PluginDescriptor FileSinkPlugin::m_pluginDescriptor = { FileSink::m_channelId, QStringLiteral("File Sink"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channelrx/remotetcpsink/remotetcpsinkplugin.cpp b/plugins/channelrx/remotetcpsink/remotetcpsinkplugin.cpp index 54079dc35..1ee9de9a8 100644 --- a/plugins/channelrx/remotetcpsink/remotetcpsinkplugin.cpp +++ b/plugins/channelrx/remotetcpsink/remotetcpsinkplugin.cpp @@ -35,7 +35,7 @@ const PluginDescriptor RemoteTCPSinkPlugin::m_pluginDescriptor = { RemoteTCPSink::m_channelId, QStringLiteral("Remote TCP channel sink"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channeltx/modam/ammodplugin.cpp b/plugins/channeltx/modam/ammodplugin.cpp index 1c7763847..f1899a28a 100644 --- a/plugins/channeltx/modam/ammodplugin.cpp +++ b/plugins/channeltx/modam/ammodplugin.cpp @@ -32,7 +32,7 @@ const PluginDescriptor AMModPlugin::m_pluginDescriptor = { AMMod::m_channelId, QStringLiteral("AM Modulator"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channeltx/modnfm/nfmmodplugin.cpp b/plugins/channeltx/modnfm/nfmmodplugin.cpp index 8219ee1a5..2b919d227 100644 --- a/plugins/channeltx/modnfm/nfmmodplugin.cpp +++ b/plugins/channeltx/modnfm/nfmmodplugin.cpp @@ -32,7 +32,7 @@ const PluginDescriptor NFMModPlugin::m_pluginDescriptor = { NFMMod::m_channelId, QStringLiteral("NFM Modulator"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index 411bf7d71..54485d601 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -68,6 +68,7 @@ SSBMod::SSBMod(DeviceAPI *deviceAPI) : m_basebandSource->setSpectrumSink(&m_spectrumVis); m_basebandSource->setInputFileStream(&m_ifstream); m_basebandSource->setChannel(this); + m_basebandSource->setCWKeyer(&m_cwKeyer); m_basebandSource->moveToThread(m_thread); applySettings(m_settings, true); diff --git a/plugins/channeltx/modssb/ssbmodplugin.cpp b/plugins/channeltx/modssb/ssbmodplugin.cpp index 7558a0b96..0e41cd5cb 100644 --- a/plugins/channeltx/modssb/ssbmodplugin.cpp +++ b/plugins/channeltx/modssb/ssbmodplugin.cpp @@ -32,7 +32,7 @@ const PluginDescriptor SSBModPlugin::m_pluginDescriptor = { SSBMod::m_channelId, QStringLiteral("SSB Modulator"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channeltx/modwfm/wfmmodplugin.cpp b/plugins/channeltx/modwfm/wfmmodplugin.cpp index bd6f6ebb4..d20076832 100644 --- a/plugins/channeltx/modwfm/wfmmodplugin.cpp +++ b/plugins/channeltx/modwfm/wfmmodplugin.cpp @@ -32,7 +32,7 @@ const PluginDescriptor WFMModPlugin::m_pluginDescriptor = { WFMMod::m_channelId, QStringLiteral("WFM Modulator"), - QStringLiteral("7.22.5"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/feature/radiosonde/radiosondegui.cpp b/plugins/feature/radiosonde/radiosondegui.cpp index 066448855..ec381a9c7 100644 --- a/plugins/feature/radiosonde/radiosondegui.cpp +++ b/plugins/feature/radiosonde/radiosondegui.cpp @@ -157,6 +157,13 @@ RadiosondeGUI::RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, F connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); m_sondeHub = SondeHub::create(); + if (m_sondeHub) + { + connect(m_sondeHub, &SondeHub::prediction, this, &RadiosondeGUI::handlePrediction); + connect(&m_predicitionTimer, &QTimer::timeout, this, &RadiosondeGUI::requestPredictions); + m_predicitionTimer.setInterval(60 * 1000); + m_predicitionTimer.setSingleShot(false); + } // Initialise chart ui->chart->setRenderHint(QPainter::Antialiasing); @@ -190,6 +197,8 @@ RadiosondeGUI::RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, F // Get updated when position changes connect(&MainCore::instance()->getSettings(), &MainSettings::preferenceChanged, this, &RadiosondeGUI::preferenceChanged); + connect(&m_positionUpdateTimer, &QTimer::timeout, this, &RadiosondeGUI::updatePosition); + m_positionUpdateTimer.setSingleShot(true); ui->radiosondes->setItemDelegateForColumn(RADIOSONDE_COL_LATITUDE, new DecimalDelegate(5, ui->radiosondes)); ui->radiosondes->setItemDelegateForColumn(RADIOSONDE_COL_LONGITUDE, new DecimalDelegate(5, ui->radiosondes)); @@ -255,12 +264,14 @@ void RadiosondeGUI::displaySettings() ui->y2->setCurrentIndex((int)m_settings.m_y2); ui->feed->setChecked(m_settings.m_feedEnabled); + ui->showPredictedPaths->setChecked(m_settings.m_showPredictedPaths); getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); getRollupContents()->arrangeRollups(); updatePosition(); + applyShowPredictedPaths(); } void RadiosondeGUI::onMenuDialogCalled(const QPoint &p) @@ -671,6 +682,10 @@ void RadiosondeGUI::updateRadiosondes(RS41Frame *message, QDateTime dateTime) MainCore::instance()->getSettings().getAltitude() ); } + + if (!found) { + requestPredictions(); + } } void RadiosondeGUI::on_radiosondes_itemSelectionChanged() @@ -906,16 +921,38 @@ void RadiosondeGUI::on_deleteAll_clicked() { QString serial = ui->radiosondes->item(row, RADIOSONDE_COL_SERIAL)->text(); // Remove from map - sendToMap(serial, "", - "", "", - "", 0.0f, - 0.0f, 0.0f, 0.0f, QDateTime(), - 0.0f); + clearFromMapFeature(serial, 0); // Remove from table ui->radiosondes->removeRow(row); // Remove from hash and free memory delete m_radiosondes.take(serial); } + deletePredictedPaths(); +} + +void RadiosondeGUI::deletePredictedPaths() +{ + for (const auto& prediction : m_predictions) { + clearFromMapFeature(prediction, 3); + } + m_predictions.clear(); +} + +void RadiosondeGUI::clearFromMapFeature(const QString& name, int type) +{ + QList mapPipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_radiosonde, "mapitems", mapPipes); + + for (const auto& pipe : mapPipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + swgMapItem->setName(new QString(name)); + swgMapItem->setImage(new QString("")); + swgMapItem->setType(type); + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_radiosonde, swgMapItem); + messageQueue->push(msg); + } } void RadiosondeGUI::makeUIConnections() @@ -926,6 +963,7 @@ void RadiosondeGUI::makeUIConnections() QObject::connect(ui->y2, qOverload(&QComboBox::currentIndexChanged), this, &RadiosondeGUI::on_y2_currentIndexChanged); QObject::connect(ui->deleteAll, &QPushButton::clicked, this, &RadiosondeGUI::on_deleteAll_clicked); QObject::connect(ui->feed, &ButtonSwitch::clicked, this, &RadiosondeGUI::on_feed_clicked); + QObject::connect(ui->showPredictedPaths, &ButtonSwitch::clicked, this, &RadiosondeGUI::on_showPredictedPaths_clicked); } void RadiosondeGUI::on_feed_clicked(bool checked) @@ -954,6 +992,28 @@ void RadiosondeGUI::feedSelect(const QPoint& p) } } +void RadiosondeGUI::on_showPredictedPaths_clicked(bool checked) +{ + m_settings.m_showPredictedPaths = checked; + m_settingsKeys.append("showPredictedPaths"); + applySettings(); + applyShowPredictedPaths(); +} + +void RadiosondeGUI::applyShowPredictedPaths() +{ + if (m_settings.m_showPredictedPaths) + { + requestPredictions(); + m_predicitionTimer.start(); + } + else + { + m_predicitionTimer.stop(); + deletePredictedPaths(); + } +} + // Get names of devices with radiosonde demods, for SondeHub Radio string QStringList RadiosondeGUI::getRadios() { @@ -963,7 +1023,7 @@ QStringList RadiosondeGUI::getRadios() for (const auto& channel : channels) { - DeviceAPI *device = mainCore->getDevice(channel.m_index); + DeviceAPI *device = mainCore->getDevice(channel.m_superIndex); if (device) { QString name = device->getHardwareId(); @@ -979,22 +1039,106 @@ QStringList RadiosondeGUI::getRadios() void RadiosondeGUI::updatePosition() { + // Limit number of position updates sent to SondeHub + const int updateTime = m_settings.m_mobile ? m_minMobilePositionUpdateTime : m_minFixedPositionUpdateTime; + if (m_sondeHub && m_settings.m_displayPosition) { - float stationLatitude = MainCore::instance()->getSettings().getLatitude(); - float stationLongitude = MainCore::instance()->getSettings().getLongitude(); - float stationAltitude = MainCore::instance()->getSettings().getAltitude(); + if (!m_lastPositionUpdate.isValid() || (m_lastPositionUpdate.secsTo(QDateTime::currentDateTime()) >= updateTime)) + { + float stationLatitude = MainCore::instance()->getSettings().getLatitude(); + float stationLongitude = MainCore::instance()->getSettings().getLongitude(); + float stationAltitude = MainCore::instance()->getSettings().getAltitude(); - m_sondeHub->updatePosition( - m_settings.m_callsign, - stationLatitude, - stationLongitude, - stationAltitude, - getRadios().join(" "), - m_settings.m_antenna, - m_settings.m_email, - m_settings.m_mobile - ); + m_sondeHub->updatePosition( + m_settings.m_callsign, + stationLatitude, + stationLongitude, + stationAltitude, + getRadios().join(" "), + m_settings.m_antenna, + m_settings.m_email, + m_settings.m_mobile + ); + + m_positionUpdateTimer.stop(); + m_lastPositionUpdate = QDateTime::currentDateTime(); + } + else + { + qint64 msecs = (updateTime * 1000) - m_lastPositionUpdate.msecsTo(QDateTime::currentDateTime()); + + if (msecs < 0) { + msecs = 0; + } + m_positionUpdateTimer.setInterval(msecs); + m_positionUpdateTimer.start(); + } + } +} + +void RadiosondeGUI::requestPredictions() +{ + if (m_sondeHub && m_settings.m_showPredictedPaths) + { + for (int row = 0; row < ui->radiosondes->rowCount(); row++) + { + QString serial = ui->radiosondes->item(row, RADIOSONDE_COL_SERIAL)->text(); + m_sondeHub->getPrediction(serial); + } + } +} + +void RadiosondeGUI::handlePrediction(const QString& serial, const QList& positions) +{ + if (positions.size() < 2) { + return; + } + + // Send to Map feature + QList mapPipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_radiosonde, "mapitems", mapPipes); + + if (mapPipes.size() > 0) + { + QString name = QString("%1_prediction").arg(serial); + + for (const auto& pipe : mapPipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem(); + + swgMapItem->setName(new QString(name)); + swgMapItem->setLatitude(positions[0].m_latitude); + swgMapItem->setLongitude(positions[0].m_longitude); + swgMapItem->setAltitude(positions[0].m_altitude); + QString image = QString("none"); + swgMapItem->setImage(new QString(image)); + swgMapItem->setImageRotation(0); + swgMapItem->setFixedPosition(true); + swgMapItem->setLabel(new QString(serial)); + swgMapItem->setAltitudeReference(0); + QList *coords = new QList(); + + for (const auto& position : positions) + { + SWGSDRangel::SWGMapCoordinate* c = new SWGSDRangel::SWGMapCoordinate(); + c->setLatitude(position.m_latitude); + c->setLongitude(position.m_longitude); + c->setAltitude(position.m_altitude); + coords->append(c); + } + + swgMapItem->setCoordinates(coords); + swgMapItem->setType(3); + + MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_radiosonde, swgMapItem); + messageQueue->push(msg); + + if (!m_predictions.contains(name)) { + m_predictions.append(name); + } + } } } diff --git a/plugins/feature/radiosonde/radiosondegui.h b/plugins/feature/radiosonde/radiosondegui.h index 124a189ea..fd6c31d47 100644 --- a/plugins/feature/radiosonde/radiosondegui.h +++ b/plugins/feature/radiosonde/radiosondegui.h @@ -103,6 +103,13 @@ private: QMenu *radiosondesMenu; // Column select context menu SondeHub *m_sondeHub; + QDateTime m_lastPositionUpdate; + QTimer m_positionUpdateTimer; + static const int m_minMobilePositionUpdateTime = 30; // In seconds + static const int m_minFixedPositionUpdateTime = 5 * 60; + + QTimer m_predicitionTimer; + QStringList m_predictions; explicit RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~RadiosondeGUI(); @@ -126,6 +133,9 @@ private: float getData(RadiosondeSettings::ChartData dataType, RadiosondeData *radiosonde, RS41Frame *message); void updatePosition(); QStringList getRadios(); + void applyShowPredictedPaths(); + void deletePredictedPaths(); + void clearFromMapFeature(const QString& name, int type); enum RadiosondeCol { RADIOSONDE_COL_SERIAL, @@ -164,6 +174,9 @@ private slots: void on_deleteAll_clicked(); void on_feed_clicked(bool checked); void feedSelect(const QPoint& p); + void on_showPredictedPaths_clicked(bool checked); + void requestPredictions(); + void handlePrediction(const QString& serial, const QList& positions); void preferenceChanged(int elementType); }; diff --git a/plugins/feature/radiosonde/radiosondegui.ui b/plugins/feature/radiosonde/radiosondegui.ui index eee177b19..106c74341 100644 --- a/plugins/feature/radiosonde/radiosondegui.ui +++ b/plugins/feature/radiosonde/radiosondegui.ui @@ -31,7 +31,7 @@ Radiosonde - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight @@ -76,20 +76,20 @@ - Qt::Vertical + Qt::Orientation::Vertical Radiosondes - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::SingleSelection + QAbstractItemView::SelectionMode::SingleSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -416,6 +416,23 @@ + + + + Show predicted paths on map + + + ... + + + + :/logarithmic.png:/logarithmic.png + + + true + + + diff --git a/plugins/feature/radiosonde/radiosondeplugin.cpp b/plugins/feature/radiosonde/radiosondeplugin.cpp index 793fc6249..49cd0fdf2 100644 --- a/plugins/feature/radiosonde/radiosondeplugin.cpp +++ b/plugins/feature/radiosonde/radiosondeplugin.cpp @@ -33,7 +33,7 @@ const PluginDescriptor RadiosondePlugin::m_pluginDescriptor = { Radiosonde::m_featureId, QStringLiteral("Radiosonde"), - QStringLiteral("7.22.1"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/feature/radiosonde/radiosondesettings.cpp b/plugins/feature/radiosonde/radiosondesettings.cpp index c45c27b90..35140dcd2 100644 --- a/plugins/feature/radiosonde/radiosondesettings.cpp +++ b/plugins/feature/radiosonde/radiosondesettings.cpp @@ -60,6 +60,7 @@ void RadiosondeSettings::resetToDefaults() m_displayPosition = false; m_mobile = false; m_email = ""; + m_showPredictedPaths = false; for (int i = 0; i < RADIOSONDES_COLUMNS; i++) { @@ -95,6 +96,7 @@ QByteArray RadiosondeSettings::serialize() const s.writeBool(17, m_displayPosition); s.writeBool(18, m_mobile); s.writeString(19, m_email); + s.writeBool(20, m_showPredictedPaths); for (int i = 0; i < RADIOSONDES_COLUMNS; i++) { @@ -159,6 +161,7 @@ bool RadiosondeSettings::deserialize(const QByteArray& data) d.readBool(17, &m_displayPosition, false); d.readBool(18, &m_mobile, false); d.readString(19, &m_email, ""); + d.readBool(20, &m_showPredictedPaths, false); for (int i = 0; i < RADIOSONDES_COLUMNS; i++) { d.readS32(300 + i, &m_radiosondesColumnIndexes[i], i); @@ -224,6 +227,9 @@ void RadiosondeSettings::applySettings(const QStringList& settingsKeys, const Ra if (settingsKeys.contains("email")) { m_email = settings.m_email; } + if (settingsKeys.contains("showPredictedPaths")) { + m_showPredictedPaths = settings.m_showPredictedPaths; + } if (settingsKeys.contains("workspaceIndex")) { m_workspaceIndex = settings.m_workspaceIndex; } @@ -292,6 +298,9 @@ QString RadiosondeSettings::getDebugString(const QStringList& settingsKeys, bool if (settingsKeys.contains("email") || force) { ostr << " m_email: " << m_email.toStdString(); } + if (settingsKeys.contains("showPredictedPaths") || force) { + ostr << " m_showPredictedPaths: " << m_showPredictedPaths; + } if (settingsKeys.contains("workspaceIndex") || force) { ostr << " m_workspaceIndex: " << m_workspaceIndex; } diff --git a/plugins/feature/radiosonde/radiosondesettings.h b/plugins/feature/radiosonde/radiosondesettings.h index 1f7071027..2112f26fa 100644 --- a/plugins/feature/radiosonde/radiosondesettings.h +++ b/plugins/feature/radiosonde/radiosondesettings.h @@ -62,6 +62,7 @@ struct RadiosondeSettings bool m_displayPosition; bool m_mobile; QString m_email; + bool m_showPredictedPaths; int m_radiosondesColumnIndexes[RADIOSONDES_COLUMNS]; int m_radiosondesColumnSizes[RADIOSONDES_COLUMNS]; diff --git a/plugins/feature/radiosonde/readme.md b/plugins/feature/radiosonde/readme.md index 6fd8e850a..55cad6f4d 100644 --- a/plugins/feature/radiosonde/readme.md +++ b/plugins/feature/radiosonde/readme.md @@ -7,7 +7,7 @@ based on data received via [Radiosonde Demodulators](../../channelrx/demodradios The chart can plot two data series vs time for the radiosonde selected in the table. -The Radiosonde feature can draw balloons objects on the [Map](../../feature/map/readme.md) feature in 2D and 3D. +The Radiosonde feature can draw balloons objects and predicted paths on the [Map](../../feature/map/readme.md) feature in 2D and 3D. Received data can be forwarded to [SondeHub](https://sondehub.org/). Your location can be displayed on the SondeHub map, as either a stationary receiver or chase car. @@ -48,6 +48,7 @@ The Radiosonde feature can plot balloons (during ascent) and parachutes (during To use, simply open a Map feature and the Radiosonde plugin will display objects based upon the data it receives from that point. Selecting a radiosonde item on the map will display a text bubble containing information from the above table. To centre the map on an item in the table, double click in the Lat or Lon columns. +Predicted paths can be displayed by checking the Show Predicted Paths button. The path is predicted by SondeHub. ![Radiosonde on map](../../../doc/img/Radiosonde_plugin_map.png) diff --git a/plugins/feature/sid/sidgui.cpp b/plugins/feature/sid/sidgui.cpp index 69c7bd3c8..2ccd5546e 100644 --- a/plugins/feature/sid/sidgui.cpp +++ b/plugins/feature/sid/sidgui.cpp @@ -2396,8 +2396,11 @@ void SIDGUI::readCSV(const QString& filename, bool autoload) if (CSV::readRow(in, &colNames)) { QList measurements; - for (int i = 0; i < colNames.size() - 1; i++) { + QList measurementIdx; + for (int i = 0; i < colNames.size() - 1; i++) + { measurements.append(nullptr); + measurementIdx.append(-1); } for (int i = 1; i < colNames.size(); i++) { @@ -2439,7 +2442,8 @@ void SIDGUI::readCSV(const QString& filename, bool autoload) } else { id = name; } - measurements[i-1] = &addMeasurements(id); + addMeasurements(id); + measurementIdx[i-1] = m_channelMeasurements.size() - 1; // Create settings, if we don't have them SIDSettings::ChannelSettings *channelSettings = m_settings.getChannelSettings(id); @@ -2482,7 +2486,11 @@ void SIDGUI::readCSV(const QString& filename, bool autoload) if (!valueStr.isEmpty()) { double value = valueStr.toDouble(); - measurements[i]->append(dateTime, value, false); + if (measurements[i]) { + measurements[i]->append(dateTime, value, false); + } else { + m_channelMeasurements[measurementIdx[i]].append(dateTime, value, false); + } } } } diff --git a/plugins/feature/sid/sidplugin.cpp b/plugins/feature/sid/sidplugin.cpp index eb9acfa02..08c050f12 100644 --- a/plugins/feature/sid/sidplugin.cpp +++ b/plugins/feature/sid/sidplugin.cpp @@ -29,7 +29,7 @@ const PluginDescriptor SIDPlugin::m_pluginDescriptor = { SIDMain::m_featureId, QStringLiteral("SID"), - QStringLiteral("7.22.1"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesink/usrpoutput/usrpoutputplugin.cpp b/plugins/samplesink/usrpoutput/usrpoutputplugin.cpp index 1cdb3820a..b693d9274 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputplugin.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputplugin.cpp @@ -36,7 +36,7 @@ const PluginDescriptor USRPOutputPlugin::m_pluginDescriptor = { QStringLiteral("USRP"), QStringLiteral("URSP Output"), - QStringLiteral("7.22.3"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/usrpinput/usrpinputplugin.cpp b/plugins/samplesource/usrpinput/usrpinputplugin.cpp index db57b3957..4457623dc 100644 --- a/plugins/samplesource/usrpinput/usrpinputplugin.cpp +++ b/plugins/samplesource/usrpinput/usrpinputplugin.cpp @@ -36,7 +36,7 @@ const PluginDescriptor USRPInputPlugin::m_pluginDescriptor = { QStringLiteral("USRP"), QStringLiteral("USRP Input"), - QStringLiteral("7.22.1"), + QStringLiteral("7.22.6"), QStringLiteral("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/sdrbase/feature/featurewebapiutils.cpp b/sdrbase/feature/featurewebapiutils.cpp index 45832bb96..84303acda 100644 --- a/sdrbase/feature/featurewebapiutils.cpp +++ b/sdrbase/feature/featurewebapiutils.cpp @@ -20,12 +20,42 @@ #include "SWGFeatureActions.h" #include "SWGMapActions.h" #include "SWGPERTesterActions.h" +#include "SWGDeviceState.h" #include "maincore.h" #include "feature/featureset.h" #include "feature/feature.h" #include "featurewebapiutils.h" +// Start feature +bool FeatureWebAPIUtils::run(int featureSetIndex, int featureIndex) +{ + Feature *feature = FeatureWebAPIUtils::getFeature(featureSetIndex, featureIndex, ""); + if (feature != nullptr) + { + SWGSDRangel::SWGDeviceState runResponse; + QString errorResponse; + int httpRC; + + runResponse.setState(new QString()); + httpRC = feature->webapiRun(true, runResponse, errorResponse); + + if (httpRC/100 != 2) + { + qWarning("FeatureWebAPIUtils::run: run error %d: %s", + httpRC, qPrintable(errorResponse)); + return false; + } + + return true; + } + else + { + qWarning("FeatureWebAPIUtils::run: no feature F%d:%d", featureSetIndex, featureIndex); + return false; + } +} + // Find the specified target on the map bool FeatureWebAPIUtils::mapFind(const QString& target, int featureSetIndex, int featureIndex) { diff --git a/sdrbase/feature/featurewebapiutils.h b/sdrbase/feature/featurewebapiutils.h index d0448892c..ddad1ae82 100644 --- a/sdrbase/feature/featurewebapiutils.h +++ b/sdrbase/feature/featurewebapiutils.h @@ -47,6 +47,7 @@ private slots: class SDRBASE_API FeatureWebAPIUtils { public: + static bool run(int featureSetIndex, int featureIndex); static bool mapFind(const QString& target, int featureSetIndex=-1, int featureIndex=-1); static bool mapSetDateTime(const QDateTime& dateTime, int featureSetIndex=-1, int featureIndex=-1); static bool skyMapFind(const QString& target, int featureSetIndex=-1, int featureIndex=-1); diff --git a/sdrbase/mainparser.cpp b/sdrbase/mainparser.cpp index 3735a5103..1456b8f25 100644 --- a/sdrbase/mainparser.cpp +++ b/sdrbase/mainparser.cpp @@ -42,7 +42,8 @@ MainParser::MainParser() : m_remoteTCPSinkPortOption("remote-tcp-port", "Remote TCP Sink port (Default 1234).", "port", "1234"), m_remoteTCPSinkHWTypeOption("remote-tcp-hwtype", "Remote TCP Sink device hardware type (Optional. E.g. RTLSDR/SDRplayV3/AirspyHF).", "hwtype"), m_remoteTCPSinkSerialOption("remote-tcp-serial", "Remote TCP Sink device serial (Optional).", "serial"), - m_listDevicesOption("list-devices", "List available physical devices.") + m_listDevicesOption("list-devices", "List available physical devices."), + m_startOption("start", "Start all devices and features") { m_serverAddress = ""; // Bind to any address @@ -56,6 +57,7 @@ MainParser::MainParser() : m_remoteTCPSinkHWType = ""; m_remoteTCPSinkSerial = ""; m_listDevices = false; + m_start = false; m_parser.setApplicationDescription("Software Defined Radio application"); m_parser.addHelpOption(); @@ -72,6 +74,7 @@ MainParser::MainParser() : m_parser.addOption(m_remoteTCPSinkHWTypeOption); m_parser.addOption(m_remoteTCPSinkSerialOption); m_parser.addOption(m_listDevicesOption); + m_parser.addOption(m_startOption); } MainParser::~MainParser() @@ -154,4 +157,8 @@ void MainParser::parse(const QCoreApplication& app) qCritical() << "You must specify a device with either --remote-tcp-hwtype or --remote-tcp-serial"; exit (EXIT_FAILURE); } + + // Start devices and features + m_start = m_parser.isSet(m_startOption); + } diff --git a/sdrbase/mainparser.h b/sdrbase/mainparser.h index d38be74ba..220db95bb 100644 --- a/sdrbase/mainparser.h +++ b/sdrbase/mainparser.h @@ -45,6 +45,7 @@ public: const QString& getRemoteTCPSinkHWType() const { return m_remoteTCPSinkHWType; } const QString& getRemoteTCPSinkSerial() const { return m_remoteTCPSinkSerial; } bool getListDevices() const { return m_listDevices; } + bool getStart() const { return m_start; } private: QString m_serverAddress; @@ -58,6 +59,7 @@ private: QString m_remoteTCPSinkHWType; QString m_remoteTCPSinkSerial; bool m_listDevices; + bool m_start; QCommandLineParser m_parser; QCommandLineOption m_serverAddressOption; @@ -71,6 +73,7 @@ private: QCommandLineOption m_remoteTCPSinkHWTypeOption; QCommandLineOption m_remoteTCPSinkSerialOption; QCommandLineOption m_listDevicesOption; + QCommandLineOption m_startOption; }; diff --git a/sdrbase/util/colormap.cpp b/sdrbase/util/colormap.cpp index e2678c648..4f7065415 100644 --- a/sdrbase/util/colormap.cpp +++ b/sdrbase/util/colormap.cpp @@ -72,6 +72,7 @@ QHash ColorMap::m_colorMaps{ {"Cubehlx2", &m_cubehlx2[0]}, {"Icy", &m_icy[0]}, {"Mint", &m_mint[0]}, + {"A.C.A.B.", &m_acab[0]}, }; const float ColorMap::m_angel[m_size] = @@ -7102,3 +7103,263 @@ const float ColorMap::m_mint[m_size] = 0.999, 0.997, 0.995, 1.000, 1.000, 1.000, }; + +const float ColorMap::m_acab[m_size] = +{ + 0.00000, 0.00000, 0.00000, + 0.01042, 0.01042, 0.01042, + 0.02083, 0.02083, 0.02083, + 0.03125, 0.03125, 0.03125, + 0.04167, 0.04167, 0.04167, + 0.05208, 0.05208, 0.05208, + 0.06250, 0.06250, 0.06250, + 0.07292, 0.07292, 0.07292, + 0.08333, 0.08333, 0.08333, + 0.09375, 0.09375, 0.09375, + 0.10417, 0.10417, 0.10417, + 0.11458, 0.11458, 0.11458, + 0.12500, 0.12500, 0.12500, + 0.13542, 0.13542, 0.13542, + 0.14583, 0.14583, 0.14583, + 0.15625, 0.15625, 0.15625, + 0.16667, 0.16667, 0.16667, + 0.17708, 0.17708, 0.17708, + 0.18750, 0.18750, 0.18750, + 0.19792, 0.19792, 0.19792, + 0.20833, 0.20833, 0.20833, + 0.21875, 0.21875, 0.21875, + 0.22917, 0.22917, 0.22917, + 0.23958, 0.23958, 0.23958, + 0.25000, 0.25000, 0.25000, + 0.26042, 0.26042, 0.26042, + 0.27083, 0.27083, 0.27083, + 0.28125, 0.28125, 0.28125, + 0.29167, 0.29167, 0.29167, + 0.30208, 0.30208, 0.30208, + 0.31250, 0.31250, 0.31250, + 0.32292, 0.32292, 0.32292, + 0.33333, 0.33333, 0.33333, + 0.32292, 0.32292, 0.35417, + 0.31250, 0.31250, 0.37500, + 0.30208, 0.30208, 0.39583, + 0.29167, 0.29167, 0.41667, + 0.28125, 0.28125, 0.43750, + 0.27083, 0.27083, 0.45833, + 0.26042, 0.26042, 0.47917, + 0.25000, 0.25000, 0.50000, + 0.23958, 0.23958, 0.52083, + 0.22917, 0.22917, 0.54167, + 0.21875, 0.21875, 0.56250, + 0.20833, 0.20833, 0.58333, + 0.19792, 0.19792, 0.60417, + 0.18750, 0.18750, 0.62500, + 0.17708, 0.17708, 0.64583, + 0.16667, 0.16667, 0.66667, + 0.15625, 0.15625, 0.68750, + 0.14583, 0.14583, 0.70833, + 0.13542, 0.13542, 0.72917, + 0.12500, 0.12500, 0.75000, + 0.11458, 0.11458, 0.77083, + 0.10417, 0.10417, 0.79167, + 0.09375, 0.09375, 0.81250, + 0.08333, 0.08333, 0.83333, + 0.07292, 0.07292, 0.85417, + 0.06250, 0.06250, 0.87500, + 0.05208, 0.05208, 0.89583, + 0.04167, 0.04167, 0.91667, + 0.03125, 0.03125, 0.93750, + 0.02083, 0.02083, 0.95833, + 0.01042, 0.01042, 0.97917, + 0.00000, 0.00000, 1.00000, + 0.00000, 0.03125, 1.00000, + 0.00000, 0.06250, 1.00000, + 0.00000, 0.09375, 1.00000, + 0.00000, 0.12500, 1.00000, + 0.00000, 0.15625, 1.00000, + 0.00000, 0.18750, 1.00000, + 0.00000, 0.21875, 1.00000, + 0.00000, 0.25000, 1.00000, + 0.00000, 0.28125, 1.00000, + 0.00000, 0.31250, 1.00000, + 0.00000, 0.34375, 1.00000, + 0.00000, 0.37500, 1.00000, + 0.00000, 0.40625, 1.00000, + 0.00000, 0.43750, 1.00000, + 0.00000, 0.46875, 1.00000, + 0.00000, 0.50000, 1.00000, + 0.00000, 0.53125, 1.00000, + 0.00000, 0.56250, 1.00000, + 0.00000, 0.59375, 1.00000, + 0.00000, 0.62500, 1.00000, + 0.00000, 0.65625, 1.00000, + 0.00000, 0.68750, 1.00000, + 0.00000, 0.71875, 1.00000, + 0.00000, 0.75000, 1.00000, + 0.00000, 0.78125, 1.00000, + 0.00000, 0.81250, 1.00000, + 0.00000, 0.84375, 1.00000, + 0.00000, 0.87500, 1.00000, + 0.00000, 0.90625, 1.00000, + 0.00000, 0.93750, 1.00000, + 0.00000, 0.96875, 1.00000, + 0.00000, 1.00000, 1.00000, + 0.00000, 1.00000, 0.96875, + 0.00000, 1.00000, 0.93750, + 0.00000, 1.00000, 0.90625, + 0.00000, 1.00000, 0.87500, + 0.00000, 1.00000, 0.84375, + 0.00000, 1.00000, 0.81250, + 0.00000, 1.00000, 0.78125, + 0.00000, 1.00000, 0.75000, + 0.00000, 1.00000, 0.71875, + 0.00000, 1.00000, 0.68750, + 0.00000, 1.00000, 0.65625, + 0.00000, 1.00000, 0.62500, + 0.00000, 1.00000, 0.59375, + 0.00000, 1.00000, 0.56250, + 0.00000, 1.00000, 0.53125, + 0.00000, 1.00000, 0.50000, + 0.00000, 1.00000, 0.46875, + 0.00000, 1.00000, 0.43750, + 0.00000, 1.00000, 0.40625, + 0.00000, 1.00000, 0.37500, + 0.00000, 1.00000, 0.34375, + 0.00000, 1.00000, 0.31250, + 0.00000, 1.00000, 0.28125, + 0.00000, 1.00000, 0.25000, + 0.00000, 1.00000, 0.21875, + 0.00000, 1.00000, 0.18750, + 0.00000, 1.00000, 0.15625, + 0.00000, 1.00000, 0.12500, + 0.00000, 1.00000, 0.09375, + 0.00000, 1.00000, 0.06250, + 0.00000, 1.00000, 0.03125, + 0.00000, 1.00000, 0.00000, + 0.03125, 1.00000, 0.00000, + 0.06250, 1.00000, 0.00000, + 0.09375, 1.00000, 0.00000, + 0.12500, 1.00000, 0.00000, + 0.15625, 1.00000, 0.00000, + 0.18750, 1.00000, 0.00000, + 0.21875, 1.00000, 0.00000, + 0.25000, 1.00000, 0.00000, + 0.28125, 1.00000, 0.00000, + 0.31250, 1.00000, 0.00000, + 0.34375, 1.00000, 0.00000, + 0.37500, 1.00000, 0.00000, + 0.40625, 1.00000, 0.00000, + 0.43750, 1.00000, 0.00000, + 0.46875, 1.00000, 0.00000, + 0.50000, 1.00000, 0.00000, + 0.53125, 1.00000, 0.00000, + 0.56250, 1.00000, 0.00000, + 0.59375, 1.00000, 0.00000, + 0.62500, 1.00000, 0.00000, + 0.65625, 1.00000, 0.00000, + 0.68750, 1.00000, 0.00000, + 0.71875, 1.00000, 0.00000, + 0.75000, 1.00000, 0.00000, + 0.78125, 1.00000, 0.00000, + 0.81250, 1.00000, 0.00000, + 0.84375, 1.00000, 0.00000, + 0.87500, 1.00000, 0.00000, + 0.90625, 1.00000, 0.00000, + 0.93750, 1.00000, 0.00000, + 0.96875, 1.00000, 0.00000, + 1.00000, 1.00000, 0.00000, + 1.00000, 0.96875, 0.00000, + 1.00000, 0.93750, 0.00000, + 1.00000, 0.90625, 0.00000, + 1.00000, 0.87500, 0.00000, + 1.00000, 0.84375, 0.00000, + 1.00000, 0.81250, 0.00000, + 1.00000, 0.78125, 0.00000, + 1.00000, 0.75000, 0.00000, + 1.00000, 0.71875, 0.00000, + 1.00000, 0.68750, 0.00000, + 1.00000, 0.65625, 0.00000, + 1.00000, 0.62500, 0.00000, + 1.00000, 0.59375, 0.00000, + 1.00000, 0.56250, 0.00000, + 1.00000, 0.53125, 0.00000, + 1.00000, 0.50000, 0.00000, + 1.00000, 0.46875, 0.00000, + 1.00000, 0.43750, 0.00000, + 1.00000, 0.40625, 0.00000, + 1.00000, 0.37500, 0.00000, + 1.00000, 0.34375, 0.00000, + 1.00000, 0.31250, 0.00000, + 1.00000, 0.28125, 0.00000, + 1.00000, 0.25000, 0.00000, + 1.00000, 0.21875, 0.00000, + 1.00000, 0.18750, 0.00000, + 1.00000, 0.15625, 0.00000, + 1.00000, 0.12500, 0.00000, + 1.00000, 0.09375, 0.00000, + 1.00000, 0.06250, 0.00000, + 1.00000, 0.03125, 0.00000, + 1.00000, 0.00000, 0.00000, + 1.00000, 0.00000, 0.03125, + 1.00000, 0.00000, 0.06250, + 1.00000, 0.00000, 0.09375, + 1.00000, 0.00000, 0.12500, + 1.00000, 0.00000, 0.15625, + 1.00000, 0.00000, 0.18750, + 1.00000, 0.00000, 0.21875, + 1.00000, 0.00000, 0.25000, + 1.00000, 0.00000, 0.28125, + 1.00000, 0.00000, 0.31250, + 1.00000, 0.00000, 0.34375, + 1.00000, 0.00000, 0.37500, + 1.00000, 0.00000, 0.40625, + 1.00000, 0.00000, 0.43750, + 1.00000, 0.00000, 0.46875, + 1.00000, 0.00000, 0.50000, + 1.00000, 0.00000, 0.53125, + 1.00000, 0.00000, 0.56250, + 1.00000, 0.00000, 0.59375, + 1.00000, 0.00000, 0.62500, + 1.00000, 0.00000, 0.65625, + 1.00000, 0.00000, 0.68750, + 1.00000, 0.00000, 0.71875, + 1.00000, 0.00000, 0.75000, + 1.00000, 0.00000, 0.78125, + 1.00000, 0.00000, 0.81250, + 1.00000, 0.00000, 0.84375, + 1.00000, 0.00000, 0.87500, + 1.00000, 0.00000, 0.90625, + 1.00000, 0.00000, 0.93750, + 1.00000, 0.00000, 0.96875, + 1.00000, 0.00000, 1.00000, + 1.00000, 0.03125, 1.00000, + 1.00000, 0.06250, 1.00000, + 1.00000, 0.09375, 1.00000, + 1.00000, 0.12500, 1.00000, + 1.00000, 0.15625, 1.00000, + 1.00000, 0.18750, 1.00000, + 1.00000, 0.21875, 1.00000, + 1.00000, 0.25000, 1.00000, + 1.00000, 0.28125, 1.00000, + 1.00000, 0.31250, 1.00000, + 1.00000, 0.34375, 1.00000, + 1.00000, 0.37500, 1.00000, + 1.00000, 0.40625, 1.00000, + 1.00000, 0.43750, 1.00000, + 1.00000, 0.46875, 1.00000, + 1.00000, 0.50000, 1.00000, + 1.00000, 0.53125, 1.00000, + 1.00000, 0.56250, 1.00000, + 1.00000, 0.59375, 1.00000, + 1.00000, 0.62500, 1.00000, + 1.00000, 0.65625, 1.00000, + 1.00000, 0.68750, 1.00000, + 1.00000, 0.71875, 1.00000, + 1.00000, 0.75000, 1.00000, + 1.00000, 0.78125, 1.00000, + 1.00000, 0.81250, 1.00000, + 1.00000, 0.84375, 1.00000, + 1.00000, 0.87500, 1.00000, + 1.00000, 0.90625, 1.00000, + 1.00000, 0.93750, 1.00000, + 1.00000, 0.96875, 1.00000, +}; diff --git a/sdrbase/util/colormap.h b/sdrbase/util/colormap.h index 110b1a04f..ae7399b27 100644 --- a/sdrbase/util/colormap.h +++ b/sdrbase/util/colormap.h @@ -69,6 +69,7 @@ private: static const float m_cubehlx2[m_size]; static const float m_icy[m_size]; static const float m_mint[m_size]; + static const float m_acab[m_size]; }; #endif diff --git a/sdrbase/util/sondehub.cpp b/sdrbase/util/sondehub.cpp index 75c00c76f..d15e665f7 100644 --- a/sdrbase/util/sondehub.cpp +++ b/sdrbase/util/sondehub.cpp @@ -126,6 +126,7 @@ void SondeHub::upload( obj.insert("subtype", subframe->getType()); } + //obj.insert("dev", true); //qDebug() << obj; QJsonArray payloads { obj @@ -182,6 +183,17 @@ void SondeHub::updatePosition( m_networkManager->put(request, data); } +void SondeHub::getPrediction(const QString& serial) +{ + QUrl url(QString("https://api.v2.sondehub.org/predictions?vehicles=%1").arg(serial)); + + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setHeader(QNetworkRequest::UserAgentHeader, "sdrangel"); + + m_networkManager->get(request); +} + void SondeHub::handleReply(QNetworkReply* reply) { if (reply) @@ -189,7 +201,89 @@ void SondeHub::handleReply(QNetworkReply* reply) if (!reply->error()) { QByteArray bytes = reply->readAll(); - //qDebug() << bytes; + QJsonDocument document = QJsonDocument::fromJson(bytes); + if (document.isObject()) + { + QJsonObject obj = document.object(); + if (obj.contains(QStringLiteral("message"))) + { + QString message = obj.value(QStringLiteral("message")).toString(); + qWarning() << "SondeHub message:" << message; + } + if (obj.contains(QStringLiteral("errors"))) + { + QJsonArray errors = obj.value(QStringLiteral("errors")).toArray(); + for (auto errorObjRef : errors) + { + QJsonObject errorObj = errorObjRef.toObject(); + if (errorObj.contains(QStringLiteral("error_message"))) + { + QString errorMessage = errorObj.value(QStringLiteral("error_message")).toString(); + qWarning() << "SondeHub error:" << errorMessage; + if (errorObj.contains(QStringLiteral("payload"))) + { + QJsonObject payload = errorObj.value(QStringLiteral("payload")).toObject(); + qWarning() << "SondeHub error:" << QJsonDocument(payload); + } + } + else + { + qWarning() << "SondeHub error:" << QJsonDocument(errorObj); + } + } + } + //qDebug() << "SondeHub::handleReply: obj" << QJsonDocument(obj); + } + else if (document.isArray()) + { + QJsonArray array = document.array(); + + for (auto arrayRef : array) + { + if (arrayRef.isObject()) + { + QJsonObject obj = arrayRef.toObject(); + + if (obj.contains(QStringLiteral("vehicle")) && obj.contains(QStringLiteral("data"))) + { + QJsonArray data; + // Perhaps a bug that data is a string rather than an array? + if (obj.value(QStringLiteral("data")).isString()) + { + QJsonDocument dataDocument = QJsonDocument::fromJson(obj.value(QStringLiteral("data")).toString().toUtf8()); + data = dataDocument.array(); + } + else + { + data = obj.value(QStringLiteral("data")).toArray(); + } + + QList positions; + for (auto dataObjRef : data) + { + QJsonObject positionObj = dataObjRef.toObject(); + Position position; + + position.m_dateTime = QDateTime::fromSecsSinceEpoch(positionObj.value(QStringLiteral("time")).toInt()); + position.m_latitude = positionObj.value(QStringLiteral("lat")).toDouble(); + position.m_longitude = positionObj.value(QStringLiteral("lon")).toDouble(); + position.m_altitude = positionObj.value(QStringLiteral("alt")).toDouble(); + positions.append(position); + } + + emit prediction(obj.value("vehicle").toString(), positions); + } + } + else + { + qDebug() << "SondeHub::handleReply:" << bytes; + } + } + } + else + { + qDebug() << "SondeHub::handleReply:" << bytes; + } } else { diff --git a/sdrbase/util/sondehub.h b/sdrbase/util/sondehub.h index 6ad663a6f..8409ac94b 100644 --- a/sdrbase/util/sondehub.h +++ b/sdrbase/util/sondehub.h @@ -36,6 +36,13 @@ protected: public: + struct Position { + float m_latitude; + float m_longitude; + float m_altitude; + QDateTime m_dateTime; + }; + static SondeHub* create(); ~SondeHub(); @@ -61,10 +68,14 @@ public: bool mobile ); + void getPrediction(const QString& serial); private slots: void handleReply(QNetworkReply* reply); +signals: + void prediction(const QString& serial, const QList& path); + private: QNetworkAccessManager *m_networkManager; diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index a3c5e9fe9..0fad8ba78 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -61,6 +61,7 @@ #include "feature/featureset.h" #include "feature/feature.h" #include "feature/featuregui.h" +#include "feature/featurewebapiutils.h" #include "mainspectrum/mainspectrumgui.h" #include "commands/commandkeyreceiver.h" #include "gui/presetitem.h" @@ -275,6 +276,9 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse InitFSM *fsm = new InitFSM(this, splash, !parser.getScratch()); connect(fsm, &InitFSM::finished, fsm, &InitFSM::deleteLater); connect(fsm, &InitFSM::finished, splash, &SDRangelSplash::deleteLater); + if (parser.getStart()) { + connect(fsm, &InitFSM::finished, this, &MainWindow::startAllAfterDelay); + } fsm->start(); qDebug() << "MainWindow::MainWindow: end"; @@ -3382,6 +3386,30 @@ void MainWindow::showAllChannels(int deviceSetIndex) } } +void MainWindow::startAllAfterDelay() +{ + // Wait a little bit before starting all devices and features, + // as some devices, such as FileSinks, can fail to start if run before initialised + // Is there a better way than this arbitrary time? + QTimer::singleShot(1000, this, &MainWindow::startAll); +} + +// Start all devices and features in all workspaces +void MainWindow::startAll() +{ + // Start all devices + for (const auto& workspace : m_workspaces) { + startAllDevices(workspace); + } + // Start all features + for (int featureSetIndex = 0; featureSetIndex < m_featureUIs.size(); featureSetIndex++) + { + for (int featureIndex = 0; featureIndex < m_featureUIs[featureSetIndex]->getNumberOfFeatures(); featureIndex++) { + FeatureWebAPIUtils::run(featureSetIndex, featureIndex); + } + } +} + // Start all devices in the workspace void MainWindow::startAllDevices(const Workspace *workspace) const { diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index 6b7baf77b..d14228fad 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -458,6 +458,8 @@ private slots: void featureMove(FeatureGUI *gui, int wsIndexDestnation); void deviceStateChanged(DeviceAPI *deviceAPI); void openFeaturePresetsDialog(QPoint p, Workspace *workspace); + void startAllAfterDelay(); + void startAll(); void startAllDevices(const Workspace *workspace) const; void stopAllDevices(const Workspace *workspace) const; void deviceMove(DeviceGUI *gui, int wsIndexDestnation); diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 0b753bfce..3cdf6f6a7 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -564,7 +564,7 @@ parts: plugin: cmake source: https://github.com/EttusResearch/uhd.git source-type: git - source-commit: v4.5.0.0 + source-commit: v4.7.0.0 source-subdir: host build-packages: - libusb-1.0-0-dev