From 070f8077b2871a262a1112b5128d18f7a065354d Mon Sep 17 00:00:00 2001 From: srcejon Date: Tue, 5 Dec 2023 12:30:25 +0000 Subject: [PATCH 1/5] Map updates: Allow selection of which device to tune to frequency. Support tuning of multiple frequencies per map item. Update maplibre to maplibregl. --- plugins/feature/map/map/map.qml | 91 +++++++++++++++++++----- plugins/feature/map/map/map_6.qml | 91 +++++++++++++++++++----- plugins/feature/map/mapgui.cpp | 7 +- plugins/feature/map/mapitem.cpp | 40 ++++++----- plugins/feature/map/mapitem.h | 6 +- plugins/feature/map/mapmodel.cpp | 34 +++++---- plugins/feature/map/mapmodel.h | 8 ++- plugins/feature/map/mapsettings.cpp | 2 +- plugins/feature/map/mapsettingsdialog.ui | 2 +- 9 files changed, 206 insertions(+), 75 deletions(-) diff --git a/plugins/feature/map/map/map.qml b/plugins/feature/map/map/map.qml index 5d807c985..2501a74e3 100644 --- a/plugins/feature/map/map/map.qml +++ b/plugins/feature/map/map/map.qml @@ -269,12 +269,24 @@ Item { mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) } } else if (mouse.button === Qt.RightButton) { - if (frequency > 0) { - freqMenuItem.text = "Set frequency to " + frequencyString - freqMenuItem.enabled = true - } else { - freqMenuItem.text = "No frequency available" - freqMenuItem.enabled = false + menuItems.clear() + menus.clear() + if (frequencies.length > 0) { + var deviceSets = mapModel.getDeviceSets() + for (var i = 0; i < deviceSets.length; i++) { + menus.append({ + title: "Set " + deviceSets[i] + " to...", + deviceSet: i + }) + for (var j = 0; j < frequencies.length; j++) { + menuItems.append({ + text: frequencyStrings[j], + frequency: frequencies[j], + deviceSet: deviceSets[i], + menuIndex: i + }) + } + } } var c = mapPtr.toCoordinate(Qt.point(mouse.x, mouse.y)) coordsMenuItem.text = "Coords: " + c.latitude.toFixed(6) + ", " + c.longitude.toFixed(6) @@ -308,29 +320,42 @@ Item { mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) } } else if (mouse.button === Qt.RightButton) { - if (frequency > 0) { - freqMenuItem.text = "Set frequency to " + frequencyString - freqMenuItem.enabled = true - } else { - freqMenuItem.text = "No frequency available" - freqMenuItem.enabled = false + menuItems.clear() + menus.clear() + if (frequencies.length > 0) { + var deviceSets = mapModel.getDeviceSets() + for (var i = 0; i < deviceSets.length; i++) { + menus.append({ + title: "Set " + deviceSets[i] + " to...", + deviceSet: i + }) + for (var j = 0; j < frequencies.length; j++) { + menuItems.append({ + text: frequencyStrings[j], + frequency: frequencies[j], + deviceSet: deviceSets[i], + menuIndex: i + }) + } + } } var c = mapPtr.toCoordinate(Qt.point(mouse.x, mouse.y)) coordsMenuItem.text = "Coords: " + c.latitude.toFixed(6) + ", " + c.longitude.toFixed(6) contextMenu.popup() } } + ListModel { + id: menus + } + ListModel { + id: menuItems + } Menu { id: contextMenu MenuItem { text: "Set as target" onTriggered: target = true } - MenuItem { - id: freqMenuItem - text: "Not set" - onTriggered: mapModel.setFrequency(frequency) - } MenuItem { text: "Move to front" onTriggered: mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) @@ -347,6 +372,38 @@ Item { id: coordsMenuItem text: "" } + Instantiator { + model: menus + delegate: Menu { + //cascade: true + id: contextSubMenu + title: model.title + } + onObjectAdded: function(index, object) { + contextMenu.insertMenu(index, object) + } + onObjectRemoved: function(index, object) { + contextMenu.removeMenu(object) + } + } + Instantiator { + model: menuItems + delegate: MenuItem { + text: model.text + onTriggered: mapModel.setFrequency(model.frequency, model.deviceSet) + } + onObjectAdded: function(index, object) { + // index is index in to menuItems model + // object is the MenuItem + var menuItem = menuItems.get(index) + var menu = menus.get(menuItem.menuIndex) + contextMenu.menuAt(menuItem.menuIndex).insertItem(index, object) + } + onObjectRemoved: function(index, object) { + // Can't use menuItems.get(index) here, as already removed from model + object.menu.removeItem(object) + } + } } } } diff --git a/plugins/feature/map/map/map_6.qml b/plugins/feature/map/map/map_6.qml index 897b93657..a774e695c 100644 --- a/plugins/feature/map/map/map_6.qml +++ b/plugins/feature/map/map/map_6.qml @@ -282,12 +282,24 @@ Item { mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) } } else if (mouse.button === Qt.RightButton) { - if (frequency > 0) { - freqMenuItem.text = "Set frequency to " + frequencyString - freqMenuItem.enabled = true - } else { - freqMenuItem.text = "No frequency available" - freqMenuItem.enabled = false + menuItems.clear() + menus.clear() + if (frequencies.length > 0) { + var deviceSets = mapModel.getDeviceSets() + for (var i = 0; i < deviceSets.length; i++) { + menus.append({ + title: "Set " + deviceSets[i] + " to...", + deviceSet: i + }) + for (var j = 0; j < frequencies.length; j++) { + menuItems.append({ + text: frequencyStrings[j], + frequency: frequencies[j], + deviceSet: deviceSets[i], + menuIndex: i + }) + } + } } var c = mapPtr.map.toCoordinate(Qt.point(mouse.x, mouse.y)) coordsMenuItem.text = "Coords: " + c.latitude.toFixed(6) + ", " + c.longitude.toFixed(6) @@ -321,29 +333,42 @@ Item { mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) } } else if (mouse.button === Qt.RightButton) { - if (frequency > 0) { - freqMenuItem.text = "Set frequency to " + frequencyString - freqMenuItem.enabled = true - } else { - freqMenuItem.text = "No frequency available" - freqMenuItem.enabled = false + menuItems.clear() + menus.clear() + if (frequencies.length > 0) { + var deviceSets = mapModel.getDeviceSets() + for (var i = 0; i < deviceSets.length; i++) { + menus.append({ + title: "Set " + deviceSets[i] + " to...", + deviceSet: i + }) + for (var j = 0; j < frequencies.length; j++) { + menuItems.append({ + text: frequencyStrings[j], + frequency: frequencies[j], + deviceSet: deviceSets[i], + menuIndex: i + }) + } + } } var c = mapPtr.map.toCoordinate(Qt.point(mouse.x, mouse.y)) coordsMenuItem.text = "Coords: " + c.latitude.toFixed(6) + ", " + c.longitude.toFixed(6) contextMenu.popup() } } + ListModel { + id: menus + } + ListModel { + id: menuItems + } Menu { id: contextMenu MenuItem { text: "Set as target" onTriggered: target = true } - MenuItem { - id: freqMenuItem - text: "Not set" - onTriggered: mapModel.setFrequency(frequency) - } MenuItem { text: "Move to front" onTriggered: mapModel.moveToFront(mapModelFiltered.mapRowToSource(index)) @@ -360,6 +385,38 @@ Item { id: coordsMenuItem text: "" } + Instantiator { + model: menus + delegate: Menu { + //cascade: true + id: contextSubMenu + title: model.title + } + onObjectAdded: function(index, object) { + contextMenu.insertMenu(index, object) + } + onObjectRemoved: function(index, object) { + contextMenu.removeMenu(object) + } + } + Instantiator { + model: menuItems + delegate: MenuItem { + text: model.text + onTriggered: mapModel.setFrequency(model.frequency, model.deviceSet) + } + onObjectAdded: function(index, object) { + // index is index in to menuItems model + // object is the MenuItem + var menuItem = menuItems.get(index) + var menu = menus.get(menuItem.menuIndex) + contextMenu.menuAt(menuItem.menuIndex).insertItem(index, object) + } + onObjectRemoved: function(index, object) { + // Can't use menuItems.get(index) here, as already removed from model + object.menu.removeItem(object) + } + } } } } diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index b0c3ac652..f1c9df910 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -1189,11 +1189,12 @@ void MapGUI::applyMap2DSettings(bool reloadMap) if (!m_settings.m_mapBoxStyles.isEmpty()) parameters["mapboxgl.mapping.additional_style_urls"] = m_settings.m_mapBoxStyles; } - if (m_settings.m_mapProvider == "maplibre") + if (m_settings.m_mapProvider == "maplibregl") { - parameters["maplibre.access_token"] = m_settings.m_mapBoxAPIKey; + parameters["maplibregl.settings_template"] = "maptiler"; // Or "mapbox" + parameters["maplibregl.access_token"] = m_settings.m_maptilerAPIKey; if (!m_settings.m_mapBoxStyles.isEmpty()) - parameters["maplibre.mapping.additional_style_urls"] = m_settings.m_mapBoxStyles; + parameters["maplibregl.mapping.additional_style_urls"] = m_settings.m_mapBoxStyles; } if (m_settings.m_mapProvider == "osm") { diff --git a/plugins/feature/map/mapitem.cpp b/plugins/feature/map/mapitem.cpp index 9caa819e3..bfe9b1728 100644 --- a/plugins/feature/map/mapitem.cpp +++ b/plugins/feature/map/mapitem.cpp @@ -90,7 +90,7 @@ void ObjectMapItem::update(SWGSDRangel::SWGMapItem *mapItem) m_animations.append(new CesiumInterface::Animation(animation)); } } - findFrequency(); + findFrequencies(); if (!m_fixedPosition) { updateTrack(mapItem->getTrack()); @@ -192,29 +192,33 @@ void PolylineMapItem::update(SWGSDRangel::SWGMapItem *mapItem) m_bounds = QGeoRectangle(QGeoCoordinate(latMax, lonMin), QGeoCoordinate(latMin, lonMax)); } -void ObjectMapItem::findFrequency() +// Look for a frequency in the text for this object +void ObjectMapItem::findFrequencies() { - // Look for a frequency in the text for this object - QRegExp re("(([0-9]+(\\.[0-9]+)?) *([kMG])?Hz)"); - if (re.indexIn(m_text) != -1) + m_frequencies.clear(); + m_frequencyStrings.clear(); + + const QRegularExpression re("(([0-9]+(\\.[0-9]+)?) *([kMG])?Hz)"); + QRegularExpressionMatchIterator itr = re.globalMatch(m_text); + while (itr.hasNext()) { - QStringList capture = re.capturedTexts(); - m_frequency = capture[2].toDouble(); + QRegularExpressionMatch match = itr.next(); + QStringList capture = match.capturedTexts(); + double frequency = capture[2].toDouble(); + if (capture.length() == 5) { QChar unit = capture[4][0]; - if (unit == 'k') - m_frequency *= 1000.0; - else if (unit == 'M') - m_frequency *= 1000000.0; - else if (unit == 'G') - m_frequency *= 1000000000.0; + if (unit == 'k') { + frequency *= 1000; + } else if (unit == 'M') { + frequency *= 1000000; + } else if (unit == 'G') { + frequency *= 1000000000; + } } - m_frequencyString = capture[0]; - } - else - { - m_frequency = 0.0; + m_frequencies.append((qint64)frequency); + m_frequencyStrings.append(capture[0]); } } diff --git a/plugins/feature/map/mapitem.h b/plugins/feature/map/mapitem.h index b10d22295..f49b9e1c3 100644 --- a/plugins/feature/map/mapitem.h +++ b/plugins/feature/map/mapitem.h @@ -77,7 +77,7 @@ public: void update(SWGSDRangel::SWGMapItem *mapItem) override; protected: - void findFrequency(); + void findFrequencies(); void updateTrack(QList *track); void updatePredictedTrack(QList *track); @@ -92,8 +92,8 @@ protected: QString m_image; int m_imageRotation; QString m_text; - double m_frequency; // Frequency to set - QString m_frequencyString; + QList m_frequencies; // Frequencies that can be tuned (currently only extracted from text) + QStringList m_frequencyStrings; bool m_fixedPosition; // Don't record/display track QList m_predictedTrackCoords; QList m_predictedTrackDateTimes; diff --git a/plugins/feature/map/mapmodel.cpp b/plugins/feature/map/mapmodel.cpp index 3db790af0..58f107546 100644 --- a/plugins/feature/map/mapmodel.cpp +++ b/plugins/feature/map/mapmodel.cpp @@ -516,8 +516,8 @@ QHash ObjectMapModel::roleNames() const roles[bubbleColourRole] = "bubbleColour"; roles[selectedRole] = "selected"; roles[targetRole] = "target"; - roles[frequencyRole] = "frequency"; - roles[frequencyStringRole] = "frequencyString"; + roles[frequenciesRole] = "frequencies"; + roles[frequencyStringsRole] = "frequencyStrings"; roles[predictedGroundTrack1Role] = "predictedGroundTrack1"; roles[predictedGroundTrack2Role] = "predictedGroundTrack2"; roles[groundTrack1Role] = "groundTrack1"; @@ -675,10 +675,10 @@ QVariant ObjectMapModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(m_selected[row]); case targetRole: return QVariant::fromValue(m_target == row); - case frequencyRole: - return QVariant::fromValue(mapItem->m_frequency); - case frequencyStringRole: - return QVariant::fromValue(mapItem->m_frequencyString); + case frequenciesRole: + return QVariant::fromValue(mapItem->m_frequencies); + case frequencyStringsRole: + return QVariant::fromValue(mapItem->m_frequencyStrings); case predictedGroundTrack1Role: { if ( (m_displayAllGroundTracks || (m_displaySelectedGroundTracks && m_selected[row])) @@ -780,12 +780,6 @@ void ObjectMapModel::setDisplayAllGroundTracks(bool displayGroundTracks) allUpdated(); } -void ObjectMapModel::setFrequency(double frequency) -{ - // Set as centre frequency - ChannelWebAPIUtils::setCenterFrequency(0, frequency); -} - void ObjectMapModel::track3D(int index) { if (index < m_items.count()) @@ -795,6 +789,22 @@ void ObjectMapModel::track3D(int index) } } +QStringList ObjectMapModel::getDeviceSets() const +{ + return MainCore::instance()->getDeviceSetIds(true, true, false); // FIXME: MIMO currently disabled, as we can't get channel stream indexes +} + +void ObjectMapModel::setFrequency(qint64 frequency, const QString& deviceSetId) +{ + unsigned int deviceSetIndex; + + if (MainCore::getDeviceSetIndexFromId(deviceSetId, deviceSetIndex)) + { + // Set as centre frequency + ChannelWebAPIUtils::setCenterFrequency(deviceSetIndex, frequency); + } +} + void ObjectMapModel::splitTracks(ObjectMapItem *item) { if (item->m_takenTrackCoords.size() > 1) diff --git a/plugins/feature/map/mapmodel.h b/plugins/feature/map/mapmodel.h index 4d57570de..2a038f39c 100644 --- a/plugins/feature/map/mapmodel.h +++ b/plugins/feature/map/mapmodel.h @@ -211,8 +211,8 @@ public: bubbleColourRole = MapModel::lastRole + 4, selectedRole = MapModel::lastRole + 5, targetRole = MapModel::lastRole + 6, - frequencyRole = MapModel::lastRole + 7, - frequencyStringRole = MapModel::lastRole + 8, + frequenciesRole = MapModel::lastRole + 7, + frequencyStringsRole = MapModel::lastRole + 8, predictedGroundTrack1Role = MapModel::lastRole + 9, predictedGroundTrack2Role = MapModel::lastRole + 10, groundTrack1Role = MapModel::lastRole + 11, @@ -244,8 +244,10 @@ public: void setDisplayNames(bool displayNames); void setDisplaySelectedGroundTracks(bool displayGroundTracks); void setDisplayAllGroundTracks(bool displayGroundTracks); - Q_INVOKABLE void setFrequency(double frequency); Q_INVOKABLE void track3D(int index); + Q_INVOKABLE QStringList getDeviceSets() const; + Q_INVOKABLE void setFrequency(qint64 frequency, const QString& deviceSet); + Q_INVOKABLE void viewChanged(double bottomLeftLongitude, double bottomRightLongitude); diff --git a/plugins/feature/map/mapsettings.cpp b/plugins/feature/map/mapsettings.cpp index 0ac4a7938..c280d95c7 100644 --- a/plugins/feature/map/mapsettings.cpp +++ b/plugins/feature/map/mapsettings.cpp @@ -66,7 +66,7 @@ const QStringList MapSettings::m_mapProviders = { QStringLiteral("esri"), QStringLiteral("mapbox"), QStringLiteral("mapboxgl"), - QStringLiteral("maplibre") + QStringLiteral("maplibregl") }; MapSettings::MapSettings() : diff --git a/plugins/feature/map/mapsettingsdialog.ui b/plugins/feature/map/mapsettingsdialog.ui index 6728e47c5..53f2c962c 100644 --- a/plugins/feature/map/mapsettingsdialog.ui +++ b/plugins/feature/map/mapsettingsdialog.ui @@ -95,7 +95,7 @@ - MapLibre + MapLibreGL From d989561df56211af7e95cc69b0c2b259f0e827b1 Mon Sep 17 00:00:00 2001 From: srcejon Date: Tue, 5 Dec 2023 12:32:53 +0000 Subject: [PATCH 2/5] Use common code for creating and processing device and channel Ids. --- plugins/channelrx/demodadsb/adsbdemodgui.cpp | 23 +--- plugins/channelrx/freqscanner/freqscanner.cpp | 24 +--- plugins/channelrx/freqscanner/freqscanner.h | 4 +- .../channelrx/freqscanner/freqscannergui.cpp | 12 +- .../radioastronomy/radioastronomy.cpp | 12 +- .../channelrx/radioastronomy/radioastronomy.h | 8 +- .../radioastronomy/radioastronomygui.cpp | 16 +-- .../feature/startracker/startrackerworker.cpp | 7 +- sdrbase/maincore.cpp | 127 ++++++++++++++++++ sdrbase/maincore.h | 13 +- 10 files changed, 173 insertions(+), 73 deletions(-) diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index d71460a7f..0388c84f8 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -577,12 +577,7 @@ void AircraftModel::findOnMap(int index) // Get list of frequeny scanners to use in menu QStringList AirportModel::getFreqScanners() const { - QStringList list; - std::vector channels = MainCore::instance()->getChannels("sdrangel.channel.freqscanner"); - for (const auto channel : channels) { - list.append(QString("R%1:%2").arg(channel->getDeviceSetIndex()).arg(channel->getIndexInDeviceSet())); - } - return list; + return MainCore::instance()->getChannelIds("sdrangel.channel.freqscanner"); } // Send airport frequencies to frequency scanner with given id (Rn:n) @@ -592,14 +587,10 @@ void AirportModel::sendToFreqScanner(int index, const QString& id) return; } const AirportInformation *airport = m_airports[index]; + unsigned int deviceSet, channelIndex; - const QRegularExpression re("R([0-9]+):([0-9]+)"); - QRegularExpressionMatch match = re.match(id); - if (match.hasMatch()) + if (MainCore::getDeviceAndChannelIndexFromId(id, deviceSet, channelIndex)) { - int deviceSet = match.capturedTexts()[1].toInt(); - int channelIndex = match.capturedTexts()[2].toInt(); - QJsonArray array; for (const auto airportFrequency : airport->m_frequencies) { @@ -867,12 +858,10 @@ bool NavAidModel::setData(const QModelIndex &index, const QVariant& value, int r // Set selected AM Demod to the given frequency (used to tune to ATC selected from airports on map) bool ADSBDemodGUI::setFrequency(qint64 targetFrequencyHz) { - const QRegularExpression re("R([0-9]+):([0-9]+)"); - QRegularExpressionMatch match = re.match(m_settings.m_amDemod); - if (match.hasMatch()) + unsigned int deviceSet, channelIndex; + + if (MainCore::getDeviceAndChannelIndexFromId(m_settings.m_amDemod, deviceSet, channelIndex)) { - int deviceSet = match.capturedTexts()[1].toInt(); - int channelIndex = match.capturedTexts()[2].toInt(); const int halfChannelBW = 20000/2; int dcOffset = halfChannelBW; diff --git a/plugins/channelrx/freqscanner/freqscanner.cpp b/plugins/channelrx/freqscanner/freqscanner.cpp index 274defd91..f59856762 100644 --- a/plugins/channelrx/freqscanner/freqscanner.cpp +++ b/plugins/channelrx/freqscanner/freqscanner.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -67,8 +66,8 @@ FreqScanner::FreqScanner(DeviceAPI *deviceAPI) : m_basebandSink(nullptr), m_running(false), m_basebandSampleRate(0), - m_scanDeviceSetIndex(-1), - m_scanChannelIndex(-1), + m_scanDeviceSetIndex(0), + m_scanChannelIndex(0), m_state(IDLE), m_timeoutTimer(this) { @@ -670,28 +669,19 @@ void FreqScanner::muteAll(const FreqScannerSettings& settings) } } - const QRegExp re("R([0-9]+):([0-9]+)"); for (const auto& channel : channels) { - if (re.indexIn(channel) >= 0) - { - int deviceSetIndex = re.capturedTexts()[1].toInt(); - int scanChannelIndex = re.capturedTexts()[2].toInt(); - ChannelWebAPIUtils::setAudioMute(deviceSetIndex, scanChannelIndex, true); + unsigned int deviceSetIndex, channelIndex; + + if (MainCore::getDeviceAndChannelIndexFromId(channel, deviceSetIndex, channelIndex)) { + ChannelWebAPIUtils::setAudioMute(deviceSetIndex, channelIndex, true); } } } void FreqScanner::applyChannelSetting(const QString& channel) { - const QRegExp re("R([0-9]+):([0-9]+)"); - if (re.indexIn(channel) >= 0) - { - m_scanDeviceSetIndex = re.capturedTexts()[1].toInt(); - m_scanChannelIndex = re.capturedTexts()[2].toInt(); - } - else - { + if (!MainCore::getDeviceAndChannelIndexFromId(channel, m_scanDeviceSetIndex, m_scanChannelIndex)) { qDebug() << "FreqScanner::applySettings: Failed to parse channel" << channel; } } diff --git a/plugins/channelrx/freqscanner/freqscanner.h b/plugins/channelrx/freqscanner/freqscanner.h index 9bfa0d0fb..e0e7ba2c6 100644 --- a/plugins/channelrx/freqscanner/freqscanner.h +++ b/plugins/channelrx/freqscanner/freqscanner.h @@ -370,8 +370,8 @@ private: QHash m_availableChannels; - int m_scanDeviceSetIndex; - int m_scanChannelIndex; + unsigned int m_scanDeviceSetIndex; + unsigned int m_scanChannelIndex; qint64 m_activeFrequency; QDateTime m_minFFTStartTime; int m_scannerSampleRate; diff --git a/plugins/channelrx/freqscanner/freqscannergui.cpp b/plugins/channelrx/freqscanner/freqscannergui.cpp index 7454e3ad6..8563e183e 100644 --- a/plugins/channelrx/freqscanner/freqscannergui.cpp +++ b/plugins/channelrx/freqscanner/freqscannergui.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include "device/deviceset.h" @@ -41,6 +40,7 @@ #include "gui/int64delegate.h" #include "gui/glspectrum.h" #include "channel/channelwebapiutils.h" +#include "maincore.h" #include "freqscannergui.h" #include "freqscanneraddrangedialog.h" @@ -935,15 +935,13 @@ void FreqScannerGUI::table_customContextMenuRequested(QPoint pos) qint64 frequency = ui->table->item(row, COL_FREQUENCY)->text().toLongLong(); FreqScannerSettings::FrequencySettings *frequencySettings = m_settings.getFrequencySettings(frequency); QString channel = m_settings.getChannel(frequencySettings); - const QRegExp re("R([0-9]+):([0-9]+)"); - if (re.indexIn(channel) >= 0) - { - int scanDeviceSetIndex = re.capturedTexts()[1].toInt(); - int scanChannelIndex = re.capturedTexts()[2].toInt(); + unsigned int scanDeviceSetIndex, scanChannelIndex; + if (MainCore::getDeviceAndChannelIndexFromId(channel, scanDeviceSetIndex, scanChannelIndex)) + { ButtonSwitch *startStop = ui->startStop; - QAction* findChannelMapAction = new QAction(QString("Tune R%1:%2 to %3").arg(scanDeviceSetIndex).arg(scanChannelIndex).arg(frequency), tableContextMenu); + QAction* findChannelMapAction = new QAction(QString("Tune %1 to %2").arg(channel).arg(frequency), tableContextMenu); connect(findChannelMapAction, &QAction::triggered, this, [this, scanDeviceSetIndex, scanChannelIndex, frequency, startStop]()->void { // Stop scanning diff --git a/plugins/channelrx/radioastronomy/radioastronomy.cpp b/plugins/channelrx/radioastronomy/radioastronomy.cpp index da610551e..bee6a2249 100644 --- a/plugins/channelrx/radioastronomy/radioastronomy.cpp +++ b/plugins/channelrx/radioastronomy/radioastronomy.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -479,12 +478,8 @@ void RadioAstronomy::sweepStart() m_sweep1 = m_sweep1Start; m_sweep2 = m_settings.m_sweep2Start; - const QRegExp re("F([0-9]+):([0-9]+)"); - if (re.indexIn(m_settings.m_starTracker) >= 0) + if (MainCore::getFeatureIndexFromId(m_settings.m_starTracker, m_starTrackerFeatureSetIndex, m_starTrackerFeatureIndex)) { - m_starTrackerFeatureSetIndex = re.capturedTexts()[1].toInt(); - m_starTrackerFeatureIndex = re.capturedTexts()[2].toInt(); - if (m_settings.m_sweepType == RadioAstronomySettings::SWP_AZEL) { ChannelWebAPIUtils::patchFeatureSetting(m_starTrackerFeatureSetIndex, m_starTrackerFeatureIndex, "target", "Custom Az/El"); } else if (m_settings.m_sweepType == RadioAstronomySettings::SWP_LB) { @@ -499,11 +494,8 @@ void RadioAstronomy::sweepStart() sweep2(); callOnStartTime(&RadioAstronomy::sweep1); } - else if (re.indexIn(m_settings.m_rotator) >= 0) + else if (MainCore::getFeatureIndexFromId(m_settings.m_rotator, m_rotatorFeatureSetIndex, m_rotatorFeatureIndex)) { - m_rotatorFeatureSetIndex = re.capturedTexts()[1].toInt(); - m_rotatorFeatureIndex = re.capturedTexts()[2].toInt(); - sweep2(); callOnStartTime(&RadioAstronomy::sweep1); } diff --git a/plugins/channelrx/radioastronomy/radioastronomy.h b/plugins/channelrx/radioastronomy/radioastronomy.h index 3e937aa3c..d287fe9ba 100644 --- a/plugins/channelrx/radioastronomy/radioastronomy.h +++ b/plugins/channelrx/radioastronomy/radioastronomy.h @@ -454,10 +454,10 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; - int m_starTrackerFeatureSetIndex; - int m_starTrackerFeatureIndex; - int m_rotatorFeatureSetIndex; - int m_rotatorFeatureIndex; + unsigned int m_starTrackerFeatureSetIndex; + unsigned int m_starTrackerFeatureIndex; + unsigned int m_rotatorFeatureSetIndex; + unsigned int m_rotatorFeatureIndex; float m_sweep1; // Current sweep position float m_sweep2; diff --git a/plugins/channelrx/radioastronomy/radioastronomygui.cpp b/plugins/channelrx/radioastronomy/radioastronomygui.cpp index feff288ee..af8304c6b 100644 --- a/plugins/channelrx/radioastronomy/radioastronomygui.cpp +++ b/plugins/channelrx/radioastronomy/radioastronomygui.cpp @@ -2744,12 +2744,10 @@ void RadioAstronomyGUI::on_rotator_currentTextChanged(const QString& text) void RadioAstronomyGUI::setColumnPrecisionFromRotator() { // Match rotator precision - const QRegExp re("F([0-9]+):([0-9]+)"); - if (re.indexIn(m_settings.m_rotator) >= 0) - { - int featureSetIndex = re.capturedTexts()[1].toInt(); - int featureIndex = re.capturedTexts()[2].toInt(); + unsigned int featureSetIndex, featureIndex; + if (MainCore::getFeatureIndexFromId(m_settings.m_rotator, featureSetIndex, featureIndex)) + { int precision = 0; if (ChannelWebAPIUtils::getFeatureSetting(featureSetIndex, featureIndex, "precision", precision)) { @@ -4687,12 +4685,10 @@ void RadioAstronomyGUI::addFFT(FFTMeasurement *fft, bool skipCalcs) void RadioAstronomyGUI::getRotatorData(FFTMeasurement *fft) { - const QRegExp re("F([0-9]+):([0-9]+)"); - if (re.indexIn(m_settings.m_rotator) >= 0) - { - int rotatorFeatureSetIndex = re.capturedTexts()[1].toInt(); - int rotatorFeatureIndex = re.capturedTexts()[2].toInt(); + unsigned int rotatorFeatureSetIndex, rotatorFeatureIndex; + if (MainCore::getFeatureIndexFromId(m_settings.m_rotator, rotatorFeatureSetIndex, rotatorFeatureIndex)) + { SWGSDRangel::SWGFeatureReport featureReport; double value; qDebug() << m_settings.m_rotator << rotatorFeatureSetIndex << rotatorFeatureIndex; diff --git a/plugins/feature/startracker/startrackerworker.cpp b/plugins/feature/startracker/startrackerworker.cpp index 367a599a0..81516b39e 100644 --- a/plugins/feature/startracker/startrackerworker.cpp +++ b/plugins/feature/startracker/startrackerworker.cpp @@ -501,13 +501,10 @@ void StarTrackerWorker::update() { // Get Az/El from Satellite Tracker double azimuth, elevation; + unsigned int satelliteTrackerFeatureSetIndex,satelliteTrackerFeatureIndex; - const QRegExp re("F([0-9]+):([0-9]+)"); - if (re.indexIn(m_settings.m_target) >= 0) + if (MainCore::getFeatureIndexFromId(m_settings.m_target, satelliteTrackerFeatureSetIndex, satelliteTrackerFeatureIndex)) { - int satelliteTrackerFeatureSetIndex = re.capturedTexts()[1].toInt(); - int satelliteTrackerFeatureIndex = re.capturedTexts()[2].toInt(); - if (ChannelWebAPIUtils::getFeatureReportValue(satelliteTrackerFeatureSetIndex, satelliteTrackerFeatureIndex, "targetAzimuth", azimuth) && ChannelWebAPIUtils::getFeatureReportValue(satelliteTrackerFeatureSetIndex, satelliteTrackerFeatureIndex, "targetElevation", elevation)) { diff --git a/sdrbase/maincore.cpp b/sdrbase/maincore.cpp index 5ab0c32df..d1d899d34 100644 --- a/sdrbase/maincore.cpp +++ b/sdrbase/maincore.cpp @@ -435,6 +435,121 @@ void MainCore::updateWakeLock() } #endif +QChar MainCore::getDeviceSetTypeId(const DeviceSet* deviceSet) +{ + if (deviceSet->m_deviceMIMOEngine) { + return 'M'; + } else if (deviceSet->m_deviceSinkEngine) { + return 'T'; + } else if (deviceSet->m_deviceSourceEngine) { + return 'R'; + } else { + return 'X'; // Unknown + } +} + +QString MainCore::getDeviceSetId(const DeviceSet* deviceSet) +{ + QChar type = getDeviceSetTypeId(deviceSet); + + return QString("%1%2").arg(type).arg(deviceSet->getIndex()); +} + +QString MainCore::getChannelId(const ChannelAPI* channel) +{ + std::vector deviceSets = getDeviceSets(); + DeviceSet* deviceSet = deviceSets[channel->getDeviceSetIndex()]; + QString deviceSetId = getDeviceSetId(deviceSet); + int index = channel->getIndexInDeviceSet(); + // FIXME: if (deviceSet->m_deviceMIMOEngine) { + // we should append stream index. E.g. "M0:0.0" However, only ChannelGUI seems to know what it is + return QString("%1:%2").arg(deviceSetId).arg(index); +} + +QStringList MainCore::getDeviceSetIds(bool rx, bool tx, bool mimo) +{ + QStringList list; + std::vector deviceSets = getDeviceSets(); + + for (const auto deviceSet : deviceSets) + { + DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine; + DSPDeviceSinkEngine *deviceSinkEngine = deviceSet->m_deviceSinkEngine; + DSPDeviceMIMOEngine *deviceMIMOEngine = deviceSet->m_deviceMIMOEngine; + + if (((deviceSourceEngine != nullptr) && rx) + || ((deviceSinkEngine != nullptr) && tx) + || ((deviceMIMOEngine != nullptr) && mimo)) + { + list.append(getDeviceSetId(deviceSet)); + } + } + return list; +} + +bool MainCore::getDeviceSetTypeFromId(const QString& deviceSetId, QChar &type) +{ + if (!deviceSetId.isEmpty()) + { + type = deviceSetId[0]; + return (type == 'R') || (type == 'T') || (type == 'M'); + } + else + { + return false; + } +} + +bool MainCore::getDeviceSetIndexFromId(const QString& deviceSetId, unsigned int &deviceSetIndex) +{ + const QRegularExpression re("[RTM]([0-9]+)"); + QRegularExpressionMatch match = re.match(deviceSetId); + + if (match.hasMatch()) + { + deviceSetIndex = match.capturedTexts()[1].toInt(); + return true; + } + else + { + return false; + } +} + +bool MainCore::getDeviceAndChannelIndexFromId(const QString& channelId, unsigned int &deviceSetIndex, unsigned int &channelIndex) +{ + const QRegularExpression re("[RTM]([0-9]+):([0-9]+)"); + QRegularExpressionMatch match = re.match(channelId); + + if (match.hasMatch()) + { + deviceSetIndex = match.capturedTexts()[1].toInt(); + channelIndex = match.capturedTexts()[2].toInt(); + return true; + } + else + { + return false; + } +} + +bool MainCore::getFeatureIndexFromId(const QString& featureId, unsigned int &featureSetIndex, unsigned int &featureIndex) +{ + const QRegularExpression re("[F]([0-9]+):([0-9]+)"); + QRegularExpressionMatch match = re.match(featureId); + + if (match.hasMatch()) + { + featureSetIndex = match.capturedTexts()[1].toInt(); + featureIndex = match.capturedTexts()[2].toInt(); + return true; + } + else + { + return false; + } +} + std::vector MainCore::getChannels(const QString& uri) { std::vector channels; @@ -452,3 +567,15 @@ std::vector MainCore::getChannels(const QString& uri) return channels; } + +QStringList MainCore::getChannelIds(const QString& uri) +{ + QStringList list; + std::vector channels = getChannels(uri); + + for (const auto channel : channels) { + list.append(getChannelId(channel)); + } + + return list; +} diff --git a/sdrbase/maincore.h b/sdrbase/maincore.h index 4979d0788..ee3e1e569 100644 --- a/sdrbase/maincore.h +++ b/sdrbase/maincore.h @@ -857,7 +857,6 @@ public: PluginManager *getPluginManager() const { return m_pluginManager; } std::vector& getDeviceSets() { return m_deviceSets; } std::vector& getFeatureeSets() { return m_featureSets; } - std::vector getChannels(const QString& uri); //!< Get all channels from any device set with the given URI void setLoggingOptions(); DeviceAPI *getDevice(unsigned int deviceSetIndex); ChannelAPI *getChannel(unsigned int deviceSetIndex, int channelIndex); @@ -887,6 +886,18 @@ public: // Position const QGeoPositionInfo& getPosition() const; + // Ids + QChar getDeviceSetTypeId(const DeviceSet* deviceSet); //!< Get Type Id (E.g. 'R', 'T' or 'M') for the given device set + QString getDeviceSetId(const DeviceSet* deviceSet); //!< Get Id (E.g. "R2") for the given device set + QString getChannelId(const ChannelAPI* channel); //!< Get Id (E.g. "R1:2") for the given channel + static bool getDeviceSetTypeFromId(const QString& deviceSetId, QChar &type); //!< "R1" -> 'R' + static bool getDeviceSetIndexFromId(const QString& deviceSetId, unsigned int &deviceSetIndex); //!< "R1" -> 1 + static bool getDeviceAndChannelIndexFromId(const QString& channelId, unsigned int &deviceSetIndex, unsigned int &channelIndex); //!< "R3:4" -> 3, 4 + static bool getFeatureIndexFromId(const QString& featureId, unsigned int &featureSetIndex, unsigned int &featureIndex); //!< "F0:2" -> 0, 2 + QStringList getDeviceSetIds(bool rx, bool tx, bool mimo); //!< Get list of all device set Ids. E.g: {"R0", "R1", "T1", "M2"} + std::vector getChannels(const QString& uri); //!< Get all channels from any device set with the given URI + QStringList getChannelIds(const QString& uri); //!< Get all Ids for channels from any device set with the given URI. E.g. "sdrangel.channel.xyzdemod" -> {"R2:1", "M0:0.1"} + friend class MainServer; friend class MainWindow; friend class WebAPIAdapter; From b16206068ab1b6e73cbc88a5147a0afb2c9c1db0 Mon Sep 17 00:00:00 2001 From: srcejon Date: Tue, 5 Dec 2023 12:33:45 +0000 Subject: [PATCH 3/5] Prevent crash that can occur if preset type is unknown. --- sdrgui/mainwindow.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 1b0f7741f..75fdce20f 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -1502,10 +1502,17 @@ void MainWindow::loadConfiguration(const Configuration *configuration, bool from deviceWorkspaceIndex; sampleMIMOAdd(m_workspaces[deviceWorkspaceIndex], m_workspaces[spectrumWorkspaceIndex], bestDeviceIndex); } + else + { + qDebug() << "MainWindow::loadConfiguration: Unknown preset type: " << deviceSetPreset.getPresetType(); + } - MDIUtils::restoreMDIGeometry(m_deviceUIs.back()->m_deviceGUI, deviceSetPreset.getDeviceGeometry()); - MDIUtils::restoreMDIGeometry(m_deviceUIs.back()->m_mainSpectrumGUI, deviceSetPreset.getSpectrumGeometry()); - m_deviceUIs.back()->loadDeviceSetSettings(&deviceSetPreset, m_pluginManager->getPluginAPI(), &m_workspaces, nullptr); + if (m_deviceUIs.size() > 0) + { + MDIUtils::restoreMDIGeometry(m_deviceUIs.back()->m_deviceGUI, deviceSetPreset.getDeviceGeometry()); + MDIUtils::restoreMDIGeometry(m_deviceUIs.back()->m_mainSpectrumGUI, deviceSetPreset.getSpectrumGeometry()); + m_deviceUIs.back()->loadDeviceSetSettings(&deviceSetPreset, m_pluginManager->getPluginAPI(), &m_workspaces, nullptr); + } if (waitBox) { From 8d3757907626ba440b7e2694a1c1207aa5069701 Mon Sep 17 00:00:00 2001 From: srcejon Date: Tue, 5 Dec 2023 12:34:15 +0000 Subject: [PATCH 4/5] Add support for setting center frequency on Tx devices. --- sdrbase/channel/channelwebapiutils.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sdrbase/channel/channelwebapiutils.cpp b/sdrbase/channel/channelwebapiutils.cpp index a23e83a0f..fd8be370a 100644 --- a/sdrbase/channel/channelwebapiutils.cpp +++ b/sdrbase/channel/channelwebapiutils.cpp @@ -333,10 +333,11 @@ bool ChannelWebAPIUtils::getCenterFrequency(unsigned int deviceIndex, double &fr } // Set device center frequency +// Doesn't support MIMO devices. We'd need stream index parameter bool ChannelWebAPIUtils::setCenterFrequency(unsigned int deviceIndex, double frequencyInHz) { SWGSDRangel::SWGDeviceSettings deviceSettingsResponse; - int httpRC; + int httpRC = 404; DeviceSet *deviceSet; if (getDeviceSettings(deviceIndex, deviceSettingsResponse, deviceSet)) @@ -354,8 +355,13 @@ bool ChannelWebAPIUtils::setCenterFrequency(unsigned int deviceIndex, double fre SWGSDRangel::SWGErrorResponse errorResponse2; DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource(); - - httpRC = source->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage()); + if (source) { + httpRC = source->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage()); + } + DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink(); + if (sink) { + httpRC = sink->webapiSettingsPutPatch(false, deviceSettingsKeys, deviceSettingsResponse, *errorResponse2.getMessage()); + } if (httpRC/100 == 2) { From 8240d0a9d5a8653259f068ce8309c29b04702973 Mon Sep 17 00:00:00 2001 From: srcejon Date: Tue, 5 Dec 2023 12:48:14 +0000 Subject: [PATCH 5/5] Try to fix Mac build, again. --- .github/workflows/sdrangel.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sdrangel.yml b/.github/workflows/sdrangel.yml index 9e16679b6..5ad2b6e86 100644 --- a/.github/workflows/sdrangel.yml +++ b/.github/workflows/sdrangel.yml @@ -111,9 +111,9 @@ jobs: - name: Install brew uhd package run: | rm -f /usr/local/bin/2to3* - rm -f /usr/local/bin/idle3 - rm -f /usr/local/bin/pydoc3 - rm -f /usr/local/bin/python3 + rm -f /usr/local/bin/idle3* + rm -f /usr/local/bin/pydoc3* + rm -f /usr/local/bin/python3* rm -f /usr/local/bin/python3-config brew install uhd - name: Install brew opencv package