mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	Merge branch 'fix_2283' of https://github.com/srcejon/sdrangel into fix_2283
This commit is contained in:
		
						commit
						ad46defda9
					
				
							
								
								
									
										44
									
								
								.github/workflows/mac.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								.github/workflows/mac.yml
									
									
									
									
										vendored
									
									
								
							| @ -9,12 +9,18 @@ on: | ||||
| 
 | ||||
| jobs: | ||||
|   build_mac_x64: | ||||
|     runs-on: macos-12 | ||||
|     runs-on: macos-13 | ||||
|     env: | ||||
|       MACOSX_DEPLOYMENT_TARGET: 12.0 | ||||
|     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 +46,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 +121,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: | | ||||
|  | ||||
| @ -1,3 +1,9 @@ | ||||
| sdrangel (7.22.6-1) unstable; urgency=medium | ||||
| 
 | ||||
|     * See Github release | ||||
| 
 | ||||
|    -- Edouard Griffiths, F4EXB  <f4exb06@gmail.com>  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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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($<$<COMPILE_LANGUAGE:CXX>:-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. | ||||
|  | ||||
							
								
								
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,9 @@ | ||||
| sdrangel (7.22.6-1) unstable; urgency=medium | ||||
| 
 | ||||
|     * See Github release | ||||
| 
 | ||||
|    -- Edouard Griffiths, F4EXB  <f4exb06@gmail.com>  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 | ||||
|  | ||||
							
								
								
									
										3
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @ -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=<INSTALL_DIR> | ||||
| @ -858,7 +859,7 @@ if(ENABLE_CHANNELRX_REMOTETCPSINK) | ||||
|     ExternalProject_Add(flac | ||||
|             GIT_REPOSITORY https://github.com/xiph/flac.git | ||||
|             PREFIX "${EXTERNAL_BUILD_LIBRARIES}/flac" | ||||
|             CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DINSTALL_MANPAGES=OFF -D=BUILD_SHARED_LIBS=ON -DWITH_FORTIFY_SOURCE=OFF -DWITH_STACK_PROTECTOR=PFF -DBUILD_PROGRAMS=OFF -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF -DWITH_OGG=OFF -DBUILD_DOCS=OFF | ||||
|             CMAKE_ARGS ${COMMON_CMAKE_ARGS} -DINSTALL_MANPAGES=OFF -DBUILD_SHARED_LIBS=ON -DWITH_FORTIFY_SOURCE=OFF -DWITH_STACK_PROTECTOR=PFF -DBUILD_PROGRAMS=OFF -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF -DWITH_OGG=OFF -DBUILD_DOCS=OFF | ||||
|             BUILD_BYPRODUCTS "${FLAC_LIBRARIES}" | ||||
|             INSTALL_COMMAND "" | ||||
|             TEST_COMMAND "" | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -107,7 +107,7 @@ | ||||
|            <cursorShape>PointingHandCursor</cursorShape> | ||||
|           </property> | ||||
|           <property name="focusPolicy"> | ||||
|            <enum>Qt::StrongFocus</enum> | ||||
|            <enum>Qt::FocusPolicy::StrongFocus</enum> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Demod shift frequency from center in Hz</string> | ||||
| @ -124,7 +124,7 @@ | ||||
|         <item> | ||||
|          <widget class="Line" name="line"> | ||||
|           <property name="orientation"> | ||||
|            <enum>Qt::Vertical</enum> | ||||
|            <enum>Qt::Orientation::Vertical</enum> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
| @ -186,7 +186,7 @@ | ||||
|         <item> | ||||
|          <spacer name="horizontalSpacer_4"> | ||||
|           <property name="orientation"> | ||||
|            <enum>Qt::Horizontal</enum> | ||||
|            <enum>Qt::Orientation::Horizontal</enum> | ||||
|           </property> | ||||
|           <property name="sizeHint" stdset="0"> | ||||
|            <size> | ||||
| @ -211,7 +211,7 @@ | ||||
|            <string>0000k</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|            <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
| @ -230,7 +230,7 @@ | ||||
|            <string>#000</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|            <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
| @ -265,7 +265,7 @@ | ||||
|            <string>999.99M</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|            <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
| @ -298,7 +298,7 @@ | ||||
|            <number>1</number> | ||||
|           </property> | ||||
|           <property name="orientation"> | ||||
|            <enum>Qt::Horizontal</enum> | ||||
|            <enum>Qt::Orientation::Horizontal</enum> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
| @ -317,14 +317,14 @@ | ||||
|            <string>000</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|            <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="Line" name="line_2"> | ||||
|           <property name="orientation"> | ||||
|            <enum>Qt::Vertical</enum> | ||||
|            <enum>Qt::Orientation::Vertical</enum> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
| @ -368,6 +368,12 @@ | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="squelchLevelText"> | ||||
|           <property name="minimumSize"> | ||||
|            <size> | ||||
|             <width>30</width> | ||||
|             <height>0</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Spectrum squelch level (dB)</string> | ||||
|           </property> | ||||
| @ -397,6 +403,12 @@ | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="preRecordTimeText"> | ||||
|           <property name="minimumSize"> | ||||
|            <size> | ||||
|             <width>16</width> | ||||
|             <height>0</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Squelched recoding pre-recording time (s)</string> | ||||
|           </property> | ||||
| @ -426,6 +438,12 @@ | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="postSquelchTimeText"> | ||||
|           <property name="minimumSize"> | ||||
|            <size> | ||||
|             <width>16</width> | ||||
|             <height>0</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Squelched recording post-recording time (s)</string> | ||||
|           </property> | ||||
| @ -506,7 +524,7 @@ | ||||
|            <string>...</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> | ||||
|            <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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<ObjectPipe*> mapPipes; | ||||
|     MainCore::instance()->getMessagePipes().getMessagePipes(m_radiosonde, "mapitems", mapPipes); | ||||
| 
 | ||||
|     for (const auto& pipe : mapPipes) | ||||
|     { | ||||
|         MessageQueue *messageQueue = qobject_cast<MessageQueue*>(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<int>(&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<SondeHub::Position>& positions) | ||||
| { | ||||
|     if (positions.size() < 2) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Send to Map feature
 | ||||
|     QList<ObjectPipe*> 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<MessageQueue*>(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<SWGSDRangel::SWGMapCoordinate *> *coords = new QList<SWGSDRangel::SWGMapCoordinate *>(); | ||||
| 
 | ||||
|             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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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<SondeHub::Position>& positions); | ||||
|     void preferenceChanged(int elementType); | ||||
| 
 | ||||
| }; | ||||
|  | ||||
| @ -31,7 +31,7 @@ | ||||
|    <string>Radiosonde</string> | ||||
|   </property> | ||||
|   <property name="layoutDirection"> | ||||
|    <enum>Qt::LeftToRight</enum> | ||||
|    <enum>Qt::LayoutDirection::LeftToRight</enum> | ||||
|   </property> | ||||
|   <widget class="QWidget" name="tableContainer" native="true"> | ||||
|    <property name="geometry"> | ||||
| @ -76,20 +76,20 @@ | ||||
|        </sizepolicy> | ||||
|       </property> | ||||
|       <property name="orientation"> | ||||
|        <enum>Qt::Vertical</enum> | ||||
|        <enum>Qt::Orientation::Vertical</enum> | ||||
|       </property> | ||||
|       <widget class="QTableWidget" name="radiosondes"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Radiosondes</string> | ||||
|        </property> | ||||
|        <property name="editTriggers"> | ||||
|         <set>QAbstractItemView::NoEditTriggers</set> | ||||
|         <set>QAbstractItemView::EditTrigger::NoEditTriggers</set> | ||||
|        </property> | ||||
|        <property name="selectionMode"> | ||||
|         <enum>QAbstractItemView::SingleSelection</enum> | ||||
|         <enum>QAbstractItemView::SelectionMode::SingleSelection</enum> | ||||
|        </property> | ||||
|        <property name="selectionBehavior"> | ||||
|         <enum>QAbstractItemView::SelectRows</enum> | ||||
|         <enum>QAbstractItemView::SelectionBehavior::SelectRows</enum> | ||||
|        </property> | ||||
|        <column> | ||||
|         <property name="text"> | ||||
| @ -416,6 +416,23 @@ | ||||
|             </property> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item> | ||||
|            <widget class="ButtonSwitch" name="showPredictedPaths"> | ||||
|             <property name="toolTip"> | ||||
|              <string>Show predicted paths on map</string> | ||||
|             </property> | ||||
|             <property name="text"> | ||||
|              <string>...</string> | ||||
|             </property> | ||||
|             <property name="icon"> | ||||
|              <iconset resource="../../../sdrgui/resources/res.qrc"> | ||||
|               <normaloff>:/logarithmic.png</normaloff>:/logarithmic.png</iconset> | ||||
|             </property> | ||||
|             <property name="checkable"> | ||||
|              <bool>true</bool> | ||||
|             </property> | ||||
|            </widget> | ||||
|           </item> | ||||
|          </layout> | ||||
|         </item> | ||||
|         <item> | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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; | ||||
|     } | ||||
|  | ||||
| @ -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]; | ||||
|  | ||||
| @ -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. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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) | ||||
| { | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -76,6 +76,12 @@ QString RS41Frame::toHex() | ||||
|     return m_bytes.toHex(); | ||||
| } | ||||
| 
 | ||||
| int16_t RS41Frame::getInt16(const QByteArray ba, int offset) const | ||||
| { | ||||
|     return (ba[offset] & 0xff) | ||||
|         | ((ba[offset+1] & 0xff) << 8); | ||||
| } | ||||
| 
 | ||||
| uint16_t RS41Frame::getUInt16(const QByteArray ba, int offset) const | ||||
| { | ||||
|     return (ba[offset] & 0xff) | ||||
| @ -130,7 +136,7 @@ void RS41Frame::decodeMeas(const QByteArray ba) | ||||
|     m_pressureMain = getUInt24(ba, 0x1b); | ||||
|     m_pressureRef1 = getUInt24(ba, 0x1e); | ||||
|     m_pressureRef2 = getUInt24(ba, 0x21); | ||||
|     m_pressureTemp = getUInt16(ba, 0x26) / 100.0f; | ||||
|     m_pressureTemp = getInt16(ba, 0x26) / 100.0f; | ||||
| } | ||||
| 
 | ||||
| void RS41Frame::decodeGPSInfo(const QByteArray ba) | ||||
| @ -187,7 +193,7 @@ static float waterVapourSaturationPressure(float tCelsius) | ||||
|     return p / 100.0f; | ||||
| } | ||||
| 
 | ||||
| static float calcT(int f, int f1, int f2, float r1, float r2, float *poly, float *cal) | ||||
| static float calcT(int f, int f1, int f2, float r1, float r2, const float *poly, const float *cal) | ||||
| { | ||||
|     /*float g = (float)(f2-f1) / (r2-r1);       // gain
 | ||||
|     float Rb = (f1*r2-f2*r1) / (float)(f2-f1); // offset
 | ||||
| @ -219,7 +225,7 @@ static float calcT(int f, int f1, int f2, float r1, float r2, float *poly, float | ||||
|     return tCal; | ||||
| } | ||||
| 
 | ||||
| static float calcU(int cInt, int cMin, int cMax, float c1, float c2, float T, float HT, float *capCal, float *matrixCal, float height, float *vectorPCal, float *matrixPCal) | ||||
| static float calcU(int cInt, int cMin, int cMax, float c1, float c2, float T, float HT, const float *capCal, const float *matrixCal, float height, const float *vectorPCal, const float *matrixPCal) | ||||
| { | ||||
|     //qDebug() << "cInt " << cInt << " cMin " << cMin << " cMax " << cMax << " c1 " << c1 << " c2 " << c2 << " T " << T << " HT " << HT << " capCal[0] " << capCal[0] << " capCal[1] " << capCal[1] << "height" << height;
 | ||||
| 
 | ||||
| @ -302,7 +308,7 @@ static float calcU(int cInt, int cMin, int cMax, float c1, float c2, float T, fl | ||||
|     return uCal; | ||||
| } | ||||
| 
 | ||||
| static float calcP(int f, int f1, int f2, float pressureTemp, float *cal) | ||||
| static float calcP(int f, int f1, int f2, float pressureTemp, const float *cal) | ||||
| { | ||||
|     // Convert integer measurement to scale factor
 | ||||
|     float s = (f-f1) / (float)(f2-f1); | ||||
|  | ||||
| @ -124,6 +124,7 @@ public: | ||||
|     static int getFrameLength(int frameType); | ||||
| 
 | ||||
| protected: | ||||
|     int16_t getInt16(const QByteArray ba, int offset) const; | ||||
|     uint16_t getUInt16(const QByteArray ba, int offset) const; | ||||
|     uint32_t getUInt24(const QByteArray ba, int offset) const; | ||||
|     uint32_t getUInt32(const QByteArray ba, int offset) const; | ||||
|  | ||||
| @ -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<Position> 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 | ||||
|         { | ||||
|  | ||||
| @ -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<Position>& path); | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|     QNetworkAccessManager *m_networkManager; | ||||
|  | ||||
| @ -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"; | ||||
| @ -3387,6 +3391,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 | ||||
| { | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -444,6 +444,7 @@ EMNR::G::G( | ||||
|     std::copy(Calculus::GG.begin(), Calculus::GG.end(), GG.begin()); | ||||
|     std::copy(Calculus::GGS.begin(), Calculus::GGS.end(), GGS.begin()); | ||||
| 
 | ||||
|     /* Removed as redundant and causes a stack overflow on Mac - see #2324
 | ||||
|     // We keep this pretty useless part just in case...
 | ||||
|     if ((fileb = fopen("calculus", "rb"))) | ||||
|     { | ||||
| @ -462,7 +463,7 @@ EMNR::G::G( | ||||
|             std::copy(ggs.begin(), ggs.end(), GGS.begin()); | ||||
|         } | ||||
|         fclose(fileb); | ||||
|     } | ||||
|     }*/ | ||||
| } | ||||
| 
 | ||||
| void EMNR::G::calc_gamma0() | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user