mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-07-30 20:52:26 -04:00
Freq Scanner: Add per-frequency settings. Fix freq > 2GHz.
This commit is contained in:
parent
cdcb73f33a
commit
64f33717d0
@ -249,6 +249,7 @@ bool FreqScanner::handleMessage(const Message& cmd)
|
|||||||
}
|
}
|
||||||
else if (MsgStartScan::match(cmd))
|
else if (MsgStartScan::match(cmd))
|
||||||
{
|
{
|
||||||
|
muteAll();
|
||||||
startScan();
|
startScan();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -302,6 +303,9 @@ void FreqScanner::setDeviceCenterFrequency(qint64 frequency)
|
|||||||
|
|
||||||
void FreqScanner::initScan()
|
void FreqScanner::initScan()
|
||||||
{
|
{
|
||||||
|
if (m_scanChannelIndex < 0) {
|
||||||
|
applyChannelSetting(m_settings.m_channel);
|
||||||
|
}
|
||||||
ChannelWebAPIUtils::setAudioMute(m_scanDeviceSetIndex, m_scanChannelIndex, true);
|
ChannelWebAPIUtils::setAudioMute(m_scanDeviceSetIndex, m_scanChannelIndex, true);
|
||||||
|
|
||||||
if (m_centerFrequency != m_stepStartFrequency) {
|
if (m_centerFrequency != m_stepStartFrequency) {
|
||||||
@ -319,7 +323,6 @@ void FreqScanner::initScan()
|
|||||||
|
|
||||||
void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<MsgScanResult::ScanResult>& results)
|
void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<MsgScanResult::ScanResult>& results)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (m_state)
|
switch (m_state)
|
||||||
{
|
{
|
||||||
case IDLE:
|
case IDLE:
|
||||||
@ -329,10 +332,10 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
|
|||||||
{
|
{
|
||||||
// Create ordered list of frequencies to scan
|
// Create ordered list of frequencies to scan
|
||||||
QList<qint64> frequencies;
|
QList<qint64> frequencies;
|
||||||
for (int i = 0; i < m_settings.m_frequencies.size(); i++)
|
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_settings.m_enabled[i]) {
|
if (m_settings.m_frequencySettings[i].m_enabled) {
|
||||||
frequencies.append(m_settings.m_frequencies[i]);
|
frequencies.append(m_settings.m_frequencySettings[i].m_frequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(frequencies.begin(), frequencies.end());
|
std::sort(frequencies.begin(), frequencies.end());
|
||||||
@ -390,11 +393,11 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Are any frequencies in this new range?
|
// Are any frequencies in this new range?
|
||||||
for (int i = 0; i < m_settings.m_frequencies.size(); i++)
|
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_settings.m_enabled[i]
|
if (m_settings.m_frequencySettings[i].m_enabled
|
||||||
&& (m_settings.m_frequencies[i] >= nextCenterFrequency - usableBW / 2)
|
&& (m_settings.m_frequencySettings[i].m_frequency >= nextCenterFrequency - usableBW / 2)
|
||||||
&& (m_settings.m_frequencies[i] < nextCenterFrequency + usableBW / 2))
|
&& (m_settings.m_frequencySettings[i].m_frequency < nextCenterFrequency + usableBW / 2))
|
||||||
{
|
{
|
||||||
freqInRange = true;
|
freqInRange = true;
|
||||||
break;
|
break;
|
||||||
@ -416,51 +419,52 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
|
|||||||
m_guiMessageQueue->push(msg);
|
m_guiMessageQueue->push(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int frequency = m_scanResults[0].m_frequency;
|
int frequency = -1;
|
||||||
Real maxPower = m_scanResults[0].m_power;
|
FreqScannerSettings::FrequencySettings *frequencySettings = nullptr;
|
||||||
|
FreqScannerSettings::FrequencySettings *activeFrequencySettings = nullptr;
|
||||||
|
|
||||||
if (m_settings.m_priority == FreqScannerSettings::MAX_POWER)
|
if (m_settings.m_priority == FreqScannerSettings::MAX_POWER)
|
||||||
{
|
{
|
||||||
// Find frequency with max power
|
Real maxPower = -200.0f;
|
||||||
for (int i = 1; i < m_scanResults.size(); i++)
|
|
||||||
|
// Find frequency with max power that exceeds thresholds
|
||||||
|
for (int i = 0; i < m_scanResults.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_scanResults[i].m_power > maxPower)
|
frequencySettings = m_settings.getFrequencySettings(m_scanResults[i].m_frequency);
|
||||||
|
Real threshold = m_settings.getThreshold(frequencySettings);
|
||||||
|
if (m_scanResults[i].m_power >= threshold)
|
||||||
{
|
{
|
||||||
frequency = m_scanResults[i].m_frequency;
|
if (!activeFrequencySettings || (m_scanResults[i].m_power > maxPower))
|
||||||
maxPower = m_scanResults[i].m_power;
|
{
|
||||||
|
frequency = m_scanResults[i].m_frequency;
|
||||||
|
maxPower = m_scanResults[i].m_power;
|
||||||
|
activeFrequencySettings = frequencySettings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Find first frequency in list above threshold
|
// Find first frequency in list above threshold
|
||||||
for (int j = 0; j < m_settings.m_frequencies.size(); j++)
|
for (int i = 0; i < m_scanResults.size(); i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_scanResults.size(); i++)
|
frequencySettings = m_settings.getFrequencySettings(m_scanResults[i].m_frequency);
|
||||||
|
Real threshold = m_settings.getThreshold(frequencySettings);
|
||||||
|
if (m_scanResults[i].m_power >= threshold)
|
||||||
{
|
{
|
||||||
if (m_scanResults[i].m_frequency == m_settings.m_frequencies[j])
|
frequency = m_scanResults[i].m_frequency;
|
||||||
{
|
activeFrequencySettings = frequencySettings;
|
||||||
if (m_scanResults[i].m_power >= m_settings.m_threshold)
|
break;
|
||||||
{
|
|
||||||
frequency = m_scanResults[i].m_frequency;
|
|
||||||
maxPower = m_scanResults[i].m_power;
|
|
||||||
goto found_freq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
found_freq: ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_settings.m_mode != FreqScannerSettings::SCAN_ONLY)
|
if (m_settings.m_mode != FreqScannerSettings::SCAN_ONLY)
|
||||||
{
|
{
|
||||||
// Is power above threshold
|
// Were any frequencies found to be active?
|
||||||
if (maxPower >= m_settings.m_threshold)
|
//if (maxPower >= m_settings.m_threshold)
|
||||||
|
if (activeFrequencySettings)
|
||||||
{
|
{
|
||||||
if (m_guiMessageQueue) {
|
|
||||||
m_guiMessageQueue->push(MsgReportActiveFrequency::create(frequency));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tune device/channel to frequency
|
// Tune device/channel to frequency
|
||||||
int offset;
|
int offset;
|
||||||
if ((frequency < m_centerFrequency - usableBW / 2) || (frequency >= m_centerFrequency + usableBW / 2))
|
if ((frequency < m_centerFrequency - usableBW / 2) || (frequency >= m_centerFrequency + usableBW / 2))
|
||||||
@ -494,11 +498,28 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
|
|||||||
|
|
||||||
//qDebug() << "Tuning to active freq:" << frequency << "m_centerFrequency" << m_centerFrequency << "nextCenterFrequency" << nextCenterFrequency << "offset: " << offset << "deviceset: R" << m_scanDeviceSetIndex << ":" << m_scanChannelIndex;
|
//qDebug() << "Tuning to active freq:" << frequency << "m_centerFrequency" << m_centerFrequency << "nextCenterFrequency" << nextCenterFrequency << "offset: " << offset << "deviceset: R" << m_scanDeviceSetIndex << ":" << m_scanChannelIndex;
|
||||||
|
|
||||||
|
QString channel = m_settings.m_channel;
|
||||||
|
if (!activeFrequencySettings->m_channel.isEmpty()) {
|
||||||
|
channel = activeFrequencySettings->m_channel;
|
||||||
|
}
|
||||||
|
applyChannelSetting(channel);
|
||||||
|
|
||||||
|
// Tune the channel
|
||||||
ChannelWebAPIUtils::setFrequencyOffset(m_scanDeviceSetIndex, m_scanChannelIndex, offset);
|
ChannelWebAPIUtils::setFrequencyOffset(m_scanDeviceSetIndex, m_scanChannelIndex, offset);
|
||||||
|
|
||||||
// Unmute the channel
|
// Unmute the channel
|
||||||
ChannelWebAPIUtils::setAudioMute(m_scanDeviceSetIndex, m_scanChannelIndex, false);
|
ChannelWebAPIUtils::setAudioMute(m_scanDeviceSetIndex, m_scanChannelIndex, false);
|
||||||
|
|
||||||
|
// Apply squelch
|
||||||
|
if (!activeFrequencySettings->m_squelch.isEmpty())
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
Real squelch = activeFrequencySettings->m_squelch.toFloat(&ok);
|
||||||
|
if (ok) {
|
||||||
|
ChannelWebAPIUtils::patchChannelSetting(m_scanDeviceSetIndex, m_scanChannelIndex, "squelch", squelch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_activeFrequency = frequency;
|
m_activeFrequency = frequency;
|
||||||
|
|
||||||
if (m_settings.m_mode == FreqScannerSettings::SINGLE)
|
if (m_settings.m_mode == FreqScannerSettings::SINGLE)
|
||||||
@ -514,11 +535,16 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
|
|||||||
// Wait for transmission to finish
|
// Wait for transmission to finish
|
||||||
m_state = WAIT_FOR_END_TX;
|
m_state = WAIT_FOR_END_TX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Becareful to only do this at the end here, as it can recursively call handleMessage with new settings
|
||||||
|
if (m_guiMessageQueue) {
|
||||||
|
m_guiMessageQueue->push(MsgReportActiveFrequency::create(m_activeFrequency));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_guiMessageQueue) {
|
if (m_guiMessageQueue) {
|
||||||
m_guiMessageQueue->push(MsgStatus::create(QString("Scanning: No active channels - Max power %1 dB").arg(maxPower, 0, 'f', 1)));
|
m_guiMessageQueue->push(MsgStatus::create("Scanning..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -545,7 +571,9 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait until power drops below threshold
|
// Wait until power drops below threshold
|
||||||
if (results[i].m_power < m_settings.m_threshold)
|
FreqScannerSettings::FrequencySettings *frequencySettings = m_settings.getFrequencySettings(m_activeFrequency);
|
||||||
|
Real threshold = m_settings.getThreshold(frequencySettings);
|
||||||
|
if (results[i].m_power < threshold)
|
||||||
{
|
{
|
||||||
m_timeoutTimer.setSingleShot(true);
|
m_timeoutTimer.setSingleShot(true);
|
||||||
m_timeoutTimer.start((int)(m_settings.m_retransmitTime * 1000.0));
|
m_timeoutTimer.start((int)(m_settings.m_retransmitTime * 1000.0));
|
||||||
@ -566,7 +594,9 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if power has returned to being above threshold
|
// Check if power has returned to being above threshold
|
||||||
if (results[i].m_power >= m_settings.m_threshold)
|
FreqScannerSettings::FrequencySettings *frequencySettings = m_settings.getFrequencySettings(m_activeFrequency);
|
||||||
|
Real threshold = m_settings.getThreshold(frequencySettings);
|
||||||
|
if (results[i].m_power >= threshold)
|
||||||
{
|
{
|
||||||
m_timeoutTimer.stop();
|
m_timeoutTimer.stop();
|
||||||
m_state = WAIT_FOR_END_TX;
|
m_state = WAIT_FOR_END_TX;
|
||||||
@ -598,6 +628,9 @@ void FreqScanner::calcScannerSampleRate(int channelBW, int basebandSampleRate, i
|
|||||||
// But ensure we have several bins per channel
|
// But ensure we have several bins per channel
|
||||||
// Adjust sample rate, to ensure we don't get massive FFT size
|
// Adjust sample rate, to ensure we don't get massive FFT size
|
||||||
scannerSampleRate = basebandSampleRate;
|
scannerSampleRate = basebandSampleRate;
|
||||||
|
if (scannerSampleRate < channelBW) {
|
||||||
|
channelBW = scannerSampleRate; // Prevent divide by 0
|
||||||
|
}
|
||||||
while (fftSize / (scannerSampleRate / channelBW) < minBinsPerChannel)
|
while (fftSize / (scannerSampleRate / channelBW) < minBinsPerChannel)
|
||||||
{
|
{
|
||||||
if (fftSize == maxFFTSize) {
|
if (fftSize == maxFFTSize) {
|
||||||
@ -623,6 +656,46 @@ void FreqScanner::setCenterFrequency(qint64 frequency)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mute all channels
|
||||||
|
void FreqScanner::muteAll()
|
||||||
|
{
|
||||||
|
QStringList channels;
|
||||||
|
|
||||||
|
channels.append(m_settings.m_channel);
|
||||||
|
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
|
||||||
|
{
|
||||||
|
QString channel = m_settings.m_frequencySettings[i].m_channel;
|
||||||
|
if (!channel.isEmpty() && !channels.contains(channel)) {
|
||||||
|
channels.append(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
qDebug() << "FreqScanner::applySettings: Failed to parse channel" << channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FreqScanner::applySettings(const FreqScannerSettings& settings, const QStringList& settingsKeys, bool force)
|
void FreqScanner::applySettings(const FreqScannerSettings& settings, const QStringList& settingsKeys, bool force)
|
||||||
{
|
{
|
||||||
qDebug() << "FreqScanner::applySettings:"
|
qDebug() << "FreqScanner::applySettings:"
|
||||||
@ -640,20 +713,6 @@ void FreqScanner::applySettings(const FreqScannerSettings& settings, const QStri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsKeys.contains("channel") || force)
|
|
||||||
{
|
|
||||||
const QRegExp re("R([0-9]+):([0-9]+)");
|
|
||||||
if (re.indexIn(settings.m_channel) >= 0)
|
|
||||||
{
|
|
||||||
m_scanDeviceSetIndex = re.capturedTexts()[1].toInt();
|
|
||||||
m_scanChannelIndex = re.capturedTexts()[2].toInt();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qDebug() << "FreqScanner::applySettings: Failed to parse channel" << settings.m_channel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_running)
|
if (m_running)
|
||||||
{
|
{
|
||||||
FreqScannerBaseband::MsgConfigureFreqScannerBaseband *msg = FreqScannerBaseband::MsgConfigureFreqScannerBaseband::create(settings, settingsKeys, force);
|
FreqScannerBaseband::MsgConfigureFreqScannerBaseband *msg = FreqScannerBaseband::MsgConfigureFreqScannerBaseband::create(settings, settingsKeys, force);
|
||||||
@ -670,7 +729,7 @@ void FreqScanner::applySettings(const FreqScannerSettings& settings, const QStri
|
|||||||
webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force);
|
webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsKeys.contains("frequencies")
|
if (settingsKeys.contains("frequencySettings")
|
||||||
|| settingsKeys.contains("priority")
|
|| settingsKeys.contains("priority")
|
||||||
|| settingsKeys.contains("measurement")
|
|| settingsKeys.contains("measurement")
|
||||||
|| settingsKeys.contains("mode")
|
|| settingsKeys.contains("mode")
|
||||||
@ -782,7 +841,7 @@ void FreqScanner::webapiUpdateChannelSettings(
|
|||||||
if (channelSettingsKeys.contains("threshold")) {
|
if (channelSettingsKeys.contains("threshold")) {
|
||||||
settings.m_threshold = response.getFreqScannerSettings()->getThreshold();
|
settings.m_threshold = response.getFreqScannerSettings()->getThreshold();
|
||||||
}
|
}
|
||||||
if (channelSettingsKeys.contains("frequencies"))
|
/*if (channelSettingsKeys.contains("frequencies"))
|
||||||
{
|
{
|
||||||
settings.m_frequencies.clear();
|
settings.m_frequencies.clear();
|
||||||
settings.m_enabled.clear();
|
settings.m_enabled.clear();
|
||||||
@ -801,7 +860,7 @@ void FreqScanner::webapiUpdateChannelSettings(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
if (channelSettingsKeys.contains("rgbColor")) {
|
if (channelSettingsKeys.contains("rgbColor")) {
|
||||||
settings.m_rgbColor = response.getFreqScannerSettings()->getRgbColor();
|
settings.m_rgbColor = response.getFreqScannerSettings()->getRgbColor();
|
||||||
}
|
}
|
||||||
@ -837,7 +896,7 @@ void FreqScanner::webapiUpdateChannelSettings(
|
|||||||
QList<SWGSDRangel::SWGFreqScannerFrequency *> *FreqScanner::createFrequencyList(const FreqScannerSettings& settings)
|
QList<SWGSDRangel::SWGFreqScannerFrequency *> *FreqScanner::createFrequencyList(const FreqScannerSettings& settings)
|
||||||
{
|
{
|
||||||
QList<SWGSDRangel::SWGFreqScannerFrequency *> *frequencies = new QList<SWGSDRangel::SWGFreqScannerFrequency *>();
|
QList<SWGSDRangel::SWGFreqScannerFrequency *> *frequencies = new QList<SWGSDRangel::SWGFreqScannerFrequency *>();
|
||||||
for (int i = 0; i < settings.m_frequencies.size(); i++)
|
/*for (int i = 0; i < settings.m_frequencies.size(); i++)
|
||||||
{
|
{
|
||||||
SWGSDRangel::SWGFreqScannerFrequency *frequency = new SWGSDRangel::SWGFreqScannerFrequency();
|
SWGSDRangel::SWGFreqScannerFrequency *frequency = new SWGSDRangel::SWGFreqScannerFrequency();
|
||||||
frequency->init();
|
frequency->init();
|
||||||
@ -847,7 +906,7 @@ QList<SWGSDRangel::SWGFreqScannerFrequency *> *FreqScanner::createFrequencyList(
|
|||||||
frequency->setNotes(new QString(settings.m_notes[i]));
|
frequency->setNotes(new QString(settings.m_notes[i]));
|
||||||
}
|
}
|
||||||
frequencies->append(frequency);
|
frequencies->append(frequency);
|
||||||
}
|
}*/
|
||||||
return frequencies;
|
return frequencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +407,8 @@ private:
|
|||||||
void initScan();
|
void initScan();
|
||||||
void processScanResults(const QDateTime& fftStartTime, const QList<MsgScanResult::ScanResult>& results);
|
void processScanResults(const QDateTime& fftStartTime, const QList<MsgScanResult::ScanResult>& results);
|
||||||
void setDeviceCenterFrequency(qint64 frequency);
|
void setDeviceCenterFrequency(qint64 frequency);
|
||||||
|
void applyChannelSetting(const QString& channel);
|
||||||
|
void muteAll();
|
||||||
|
|
||||||
static QList<SWGSDRangel::SWGFreqScannerFrequency *> *createFrequencyList(const FreqScannerSettings& settings);
|
static QList<SWGSDRangel::SWGFreqScannerFrequency *> *createFrequencyList(const FreqScannerSettings& settings);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
#include <QTableWidgetItem>
|
#include <QTableWidgetItem>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
#include "device/deviceset.h"
|
#include "device/deviceset.h"
|
||||||
#include "device/deviceuiset.h"
|
#include "device/deviceuiset.h"
|
||||||
@ -37,6 +38,7 @@
|
|||||||
#include "gui/dialogpositioner.h"
|
#include "gui/dialogpositioner.h"
|
||||||
#include "gui/decimaldelegate.h"
|
#include "gui/decimaldelegate.h"
|
||||||
#include "gui/frequencydelegate.h"
|
#include "gui/frequencydelegate.h"
|
||||||
|
#include "gui/int64delegate.h"
|
||||||
#include "gui/glspectrum.h"
|
#include "gui/glspectrum.h"
|
||||||
#include "channel/channelwebapiutils.h"
|
#include "channel/channelwebapiutils.h"
|
||||||
|
|
||||||
@ -103,9 +105,9 @@ bool FreqScannerGUI::handleMessage(const Message& message)
|
|||||||
m_basebandSampleRate = notif.getSampleRate();
|
m_basebandSampleRate = notif.getSampleRate();
|
||||||
if (m_basebandSampleRate != 0)
|
if (m_basebandSampleRate != 0)
|
||||||
{
|
{
|
||||||
ui->deltaFrequency->setValueRange(true, 7, 0, m_basebandSampleRate/2);
|
ui->deltaFrequency->setValueRange(true, 8, 0, m_basebandSampleRate/2);
|
||||||
ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2));
|
ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2));
|
||||||
ui->channelBandwidth->setValueRange(true, 7, 0, m_basebandSampleRate);
|
ui->channelBandwidth->setValueRange(true, 8, 0, m_basebandSampleRate);
|
||||||
}
|
}
|
||||||
if (m_channelMarker.getBandwidth() == 0) {
|
if (m_channelMarker.getBandwidth() == 0) {
|
||||||
m_channelMarker.setBandwidth(m_basebandSampleRate);
|
m_channelMarker.setBandwidth(m_basebandSampleRate);
|
||||||
@ -116,7 +118,8 @@ bool FreqScannerGUI::handleMessage(const Message& message)
|
|||||||
else if (FreqScanner::MsgReportChannels::match(message))
|
else if (FreqScanner::MsgReportChannels::match(message))
|
||||||
{
|
{
|
||||||
FreqScanner::MsgReportChannels& report = (FreqScanner::MsgReportChannels&)message;
|
FreqScanner::MsgReportChannels& report = (FreqScanner::MsgReportChannels&)message;
|
||||||
updateChannelsList(report.getChannels());
|
m_availableChannels = report.getChannels();
|
||||||
|
updateChannelsList(m_availableChannels);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (FreqScanner::MsgStatus::match(message))
|
else if (FreqScanner::MsgStatus::match(message))
|
||||||
@ -187,11 +190,14 @@ bool FreqScannerGUI::handleMessage(const Message& message)
|
|||||||
{
|
{
|
||||||
qint64 freq = results[i].m_frequency;
|
qint64 freq = results[i].m_frequency;
|
||||||
QList<QTableWidgetItem *> items = ui->table->findItems(QString::number(freq), Qt::MatchExactly);
|
QList<QTableWidgetItem *> items = ui->table->findItems(QString::number(freq), Qt::MatchExactly);
|
||||||
for (auto item : items) {
|
for (auto item : items)
|
||||||
|
{
|
||||||
int row = item->row();
|
int row = item->row();
|
||||||
QTableWidgetItem* powerItem = ui->table->item(row, COL_POWER);
|
QTableWidgetItem* powerItem = ui->table->item(row, COL_POWER);
|
||||||
powerItem->setData(Qt::DisplayRole, results[i].m_power);
|
powerItem->setData(Qt::DisplayRole, results[i].m_power);
|
||||||
bool active = results[i].m_power >= m_settings.m_threshold;
|
FreqScannerSettings::FrequencySettings *frequencySettings = m_settings.getFrequencySettings(freq);
|
||||||
|
Real threshold = m_settings.getThreshold(frequencySettings);
|
||||||
|
bool active = results[i].m_power >= threshold;
|
||||||
if (active)
|
if (active)
|
||||||
{
|
{
|
||||||
powerItem->setBackground(Qt::darkGreen);
|
powerItem->setBackground(Qt::darkGreen);
|
||||||
@ -206,10 +212,13 @@ bool FreqScannerGUI::handleMessage(const Message& message)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqScannerGUI::updateChannelsList(const QList<FreqScannerSettings::AvailableChannel>& channels)
|
void FreqScannerGUI::updateChannelsCombo(QComboBox *combo, const QList<FreqScannerSettings::AvailableChannel>& channels, const QString& channel, bool empty)
|
||||||
{
|
{
|
||||||
ui->channels->blockSignals(true);
|
combo->blockSignals(true);
|
||||||
ui->channels->clear();
|
combo->clear();
|
||||||
|
if (empty) {
|
||||||
|
combo->addItem("");
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& channel : channels)
|
for (const auto& channel : channels)
|
||||||
{
|
{
|
||||||
@ -217,21 +226,32 @@ void FreqScannerGUI::updateChannelsList(const QList<FreqScannerSettings::Availab
|
|||||||
if ((channel.m_deviceSetIndex == m_freqScanner->getDeviceSetIndex()) && (channel.m_channelIndex != m_freqScanner->getIndexInDeviceSet()))
|
if ((channel.m_deviceSetIndex == m_freqScanner->getDeviceSetIndex()) && (channel.m_channelIndex != m_freqScanner->getIndexInDeviceSet()))
|
||||||
{
|
{
|
||||||
QString name = QString("R%1:%2").arg(channel.m_deviceSetIndex).arg(channel.m_channelIndex);
|
QString name = QString("R%1:%2").arg(channel.m_deviceSetIndex).arg(channel.m_channelIndex);
|
||||||
ui->channels->addItem(name);
|
combo->addItem(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel can be created after this plugin, so select it
|
// Channel can be created after this plugin, so select it
|
||||||
// if the chosen channel appears
|
// if the chosen channel appears
|
||||||
int channelIndex = ui->channels->findText(m_settings.m_channel);
|
int channelIndex = combo->findText(channel);
|
||||||
|
|
||||||
if (channelIndex >= 0) {
|
if (channelIndex >= 0) {
|
||||||
ui->channels->setCurrentIndex(channelIndex);
|
combo->setCurrentIndex(channelIndex);
|
||||||
} else {
|
} else {
|
||||||
ui->channels->setCurrentIndex(-1); // return to nothing selected
|
combo->setCurrentIndex(-1); // return to nothing selected
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->channels->blockSignals(false);
|
combo->blockSignals(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreqScannerGUI::updateChannelsList(const QList<FreqScannerSettings::AvailableChannel>& channels)
|
||||||
|
{
|
||||||
|
updateChannelsCombo(ui->channels, channels, m_settings.m_channel, false);
|
||||||
|
|
||||||
|
for (int row = 0; row < ui->table->rowCount(); row++)
|
||||||
|
{
|
||||||
|
QComboBox *combo = qobject_cast<QComboBox *>(ui->table->cellWidget(row, COL_CHANNEL));
|
||||||
|
updateChannelsCombo(combo, channels, m_settings.m_frequencySettings[row].m_channel, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqScannerGUI::on_channels_currentIndexChanged(int index)
|
void FreqScannerGUI::on_channels_currentIndexChanged(int index)
|
||||||
@ -412,10 +432,10 @@ FreqScannerGUI::FreqScannerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
|
|||||||
|
|
||||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||||
ui->deltaFrequency->setValueRange(true, 7, 0, 9999999);
|
ui->deltaFrequency->setValueRange(true, 8, 0, 9999999);
|
||||||
|
|
||||||
ui->channelBandwidth->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
|
ui->channelBandwidth->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
|
||||||
ui->channelBandwidth->setValueRange(true, 7, 0, 9999999);
|
ui->channelBandwidth->setValueRange(true, 8, 0, 9999999);
|
||||||
|
|
||||||
m_channelMarker.setColor(Qt::yellow);
|
m_channelMarker.setColor(Qt::yellow);
|
||||||
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
|
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
|
||||||
@ -464,6 +484,9 @@ FreqScannerGUI::FreqScannerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
|
|||||||
|
|
||||||
ui->table->setItemDelegateForColumn(COL_FREQUENCY, new FrequencyDelegate("Auto", 3));
|
ui->table->setItemDelegateForColumn(COL_FREQUENCY, new FrequencyDelegate("Auto", 3));
|
||||||
ui->table->setItemDelegateForColumn(COL_POWER, new DecimalDelegate(1));
|
ui->table->setItemDelegateForColumn(COL_POWER, new DecimalDelegate(1));
|
||||||
|
ui->table->setItemDelegateForColumn(COL_CHANNEL_BW, new Int64Delegate(0, 10000000));
|
||||||
|
ui->table->setItemDelegateForColumn(COL_TH, new DecimalDelegate(1, -120.0, 0.0));
|
||||||
|
ui->table->setItemDelegateForColumn(COL_SQ, new DecimalDelegate(1, -120.0, 0.0));
|
||||||
|
|
||||||
connect(m_deviceUISet->m_spectrum->getSpectrumView(), &GLSpectrumView::updateAnnotations, this, &FreqScannerGUI::updateAnnotations);
|
connect(m_deviceUISet->m_spectrum->getSpectrumView(), &GLSpectrumView::updateAnnotations, this, &FreqScannerGUI::updateAnnotations);
|
||||||
}
|
}
|
||||||
@ -531,9 +554,9 @@ void FreqScannerGUI::displaySettings()
|
|||||||
|
|
||||||
ui->table->blockSignals(true);
|
ui->table->blockSignals(true);
|
||||||
ui->table->setRowCount(0);
|
ui->table->setRowCount(0);
|
||||||
for (int i = 0; i < m_settings.m_frequencies.size(); i++)
|
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
|
||||||
{
|
{
|
||||||
addRow(m_settings.m_frequencies[i], m_settings.m_enabled[i], m_settings.m_notes[i]);
|
addRow(m_settings.m_frequencySettings[i]);
|
||||||
updateAnnotation(i);
|
updateAnnotation(i);
|
||||||
}
|
}
|
||||||
ui->table->blockSignals(false);
|
ui->table->blockSignals(false);
|
||||||
@ -584,7 +607,7 @@ void FreqScannerGUI::on_startStop_clicked(bool checked)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqScannerGUI::addRow(qint64 frequency, bool enabled, const QString& notes)
|
void FreqScannerGUI::addRow(const FreqScannerSettings::FrequencySettings& frequencySettings)
|
||||||
{
|
{
|
||||||
int row = ui->table->rowCount();
|
int row = ui->table->rowCount();
|
||||||
ui->table->setRowCount(row + 1);
|
ui->table->setRowCount(row + 1);
|
||||||
@ -594,11 +617,11 @@ void FreqScannerGUI::addRow(qint64 frequency, bool enabled, const QString& notes
|
|||||||
annotationItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
annotationItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
ui->table->setItem(row, COL_ANNOTATION, annotationItem);
|
ui->table->setItem(row, COL_ANNOTATION, annotationItem);
|
||||||
|
|
||||||
ui->table->setItem(row, COL_FREQUENCY, new QTableWidgetItem(QString("%1").arg(frequency)));
|
ui->table->setItem(row, COL_FREQUENCY, new QTableWidgetItem(QString("%1").arg(frequencySettings.m_frequency)));
|
||||||
|
|
||||||
QTableWidgetItem *enableItem = new QTableWidgetItem();
|
QTableWidgetItem *enableItem = new QTableWidgetItem();
|
||||||
enableItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
enableItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
||||||
enableItem->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
|
enableItem->setCheckState(frequencySettings.m_enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
ui->table->setItem(row, COL_ENABLE, enableItem);
|
ui->table->setItem(row, COL_ENABLE, enableItem);
|
||||||
|
|
||||||
QTableWidgetItem* powerItem = new QTableWidgetItem();
|
QTableWidgetItem* powerItem = new QTableWidgetItem();
|
||||||
@ -610,13 +633,40 @@ void FreqScannerGUI::addRow(qint64 frequency, bool enabled, const QString& notes
|
|||||||
ui->table->setItem(row, COL_ACTIVE_COUNT, activeCountItem);
|
ui->table->setItem(row, COL_ACTIVE_COUNT, activeCountItem);
|
||||||
activeCountItem->setData(Qt::DisplayRole, 0);
|
activeCountItem->setData(Qt::DisplayRole, 0);
|
||||||
|
|
||||||
QTableWidgetItem* notesItem = new QTableWidgetItem(notes);
|
QTableWidgetItem* notesItem = new QTableWidgetItem(frequencySettings.m_notes);
|
||||||
ui->table->setItem(row, COL_NOTES, notesItem);
|
ui->table->setItem(row, COL_NOTES, notesItem);
|
||||||
|
|
||||||
|
QComboBox *channelComboBox = new QComboBox();
|
||||||
|
updateChannelsCombo(channelComboBox, m_availableChannels, frequencySettings.m_channel, true);
|
||||||
|
ui->table->setCellWidget(row, COL_CHANNEL, channelComboBox);
|
||||||
|
connect(channelComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_table_channel_currentIndexChanged);
|
||||||
|
|
||||||
|
QTableWidgetItem* channelBandwidthItem = new QTableWidgetItem(frequencySettings.m_channelBandwidth);
|
||||||
|
ui->table->setItem(row, COL_CHANNEL_BW, channelBandwidthItem);
|
||||||
|
|
||||||
|
QTableWidgetItem* thresholdItem = new QTableWidgetItem(frequencySettings.m_threshold);
|
||||||
|
ui->table->setItem(row, COL_TH, thresholdItem);
|
||||||
|
|
||||||
|
QTableWidgetItem* squelchItem = new QTableWidgetItem(frequencySettings.m_squelch);
|
||||||
|
ui->table->setItem(row, COL_SQ, squelchItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreqScannerGUI::on_table_channel_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
QComboBox *combo = qobject_cast<QComboBox *>(sender());
|
||||||
|
QModelIndex tableIndex = ui->table->indexAt(combo->pos());
|
||||||
|
on_table_cellChanged(tableIndex.row(), tableIndex.column());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqScannerGUI::on_addSingle_clicked()
|
void FreqScannerGUI::on_addSingle_clicked()
|
||||||
{
|
{
|
||||||
addRow(0, true);
|
FreqScannerSettings::FrequencySettings frequencySettings;
|
||||||
|
frequencySettings.m_frequency = 0;
|
||||||
|
frequencySettings.m_enabled = true;
|
||||||
|
addRow(frequencySettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqScannerGUI::on_addRange_clicked()
|
void FreqScannerGUI::on_addRange_clicked()
|
||||||
@ -626,11 +676,15 @@ void FreqScannerGUI::on_addRange_clicked()
|
|||||||
if (dialog.exec())
|
if (dialog.exec())
|
||||||
{
|
{
|
||||||
blockApplySettings(true);
|
blockApplySettings(true);
|
||||||
for (const auto f : dialog.m_frequencies) {
|
for (const auto f : dialog.m_frequencies)
|
||||||
addRow(f, true);
|
{
|
||||||
|
FreqScannerSettings::FrequencySettings frequencySettings;
|
||||||
|
frequencySettings.m_frequency = f;
|
||||||
|
frequencySettings.m_enabled = true;
|
||||||
|
addRow(frequencySettings);
|
||||||
}
|
}
|
||||||
blockApplySettings(false);
|
blockApplySettings(false);
|
||||||
applySetting("frequencies");
|
applySetting("frequencySettings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,11 +696,9 @@ void FreqScannerGUI::on_remove_clicked()
|
|||||||
{
|
{
|
||||||
int row = ui->table->row(item);
|
int row = ui->table->row(item);
|
||||||
ui->table->removeRow(row);
|
ui->table->removeRow(row);
|
||||||
m_settings.m_frequencies.removeAt(row); // table_cellChanged isn't called for removeRow
|
m_settings.m_frequencySettings.removeAt(row);
|
||||||
m_settings.m_enabled.removeAt(row);
|
|
||||||
m_settings.m_notes.removeAt(row);
|
|
||||||
}
|
}
|
||||||
applySetting("frequencies");
|
applySetting("frequencySettings");
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqScannerGUI::on_removeInactive_clicked()
|
void FreqScannerGUI::on_removeInactive_clicked()
|
||||||
@ -656,12 +708,10 @@ void FreqScannerGUI::on_removeInactive_clicked()
|
|||||||
if (ui->table->item(i, COL_ACTIVE_COUNT)->data(Qt::DisplayRole).toInt() == 0)
|
if (ui->table->item(i, COL_ACTIVE_COUNT)->data(Qt::DisplayRole).toInt() == 0)
|
||||||
{
|
{
|
||||||
ui->table->removeRow(i);
|
ui->table->removeRow(i);
|
||||||
m_settings.m_frequencies.removeAt(i); // table_cellChanged isn't called for removeRow
|
m_settings.m_frequencySettings.removeAt(i);
|
||||||
m_settings.m_enabled.removeAt(i);
|
|
||||||
m_settings.m_notes.removeAt(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applySetting("frequencies");
|
applySetting("frequencySettings");
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<QTableWidgetItem*> takeRow(QTableWidget* table, int row)
|
static QList<QTableWidgetItem*> takeRow(QTableWidget* table, int row)
|
||||||
@ -730,26 +780,49 @@ void FreqScannerGUI::on_table_cellChanged(int row, int column)
|
|||||||
if (column == COL_FREQUENCY)
|
if (column == COL_FREQUENCY)
|
||||||
{
|
{
|
||||||
qint64 value = item->text().toLongLong();
|
qint64 value = item->text().toLongLong();
|
||||||
while (m_settings.m_frequencies.size() <= row)
|
while (m_settings.m_frequencySettings.size() <= row)
|
||||||
{
|
{
|
||||||
m_settings.m_frequencies.append(0);
|
FreqScannerSettings::FrequencySettings frequencySettings;
|
||||||
m_settings.m_enabled.append(true);
|
frequencySettings.m_frequency = 0;
|
||||||
m_settings.m_notes.append("");
|
frequencySettings.m_enabled = true;
|
||||||
|
m_settings.m_frequencySettings.append(frequencySettings);
|
||||||
}
|
}
|
||||||
m_settings.m_frequencies[row] = value;
|
m_settings.m_frequencySettings[row].m_frequency = value;
|
||||||
updateAnnotation(row);
|
updateAnnotation(row);
|
||||||
applySetting("frequencies");
|
applySetting("frequencySettings");
|
||||||
}
|
}
|
||||||
else if (column == COL_ENABLE)
|
else if (column == COL_ENABLE)
|
||||||
{
|
{
|
||||||
m_settings.m_enabled[row] = item->checkState() == Qt::Checked;
|
m_settings.m_frequencySettings[row].m_enabled = item->checkState() == Qt::Checked;
|
||||||
applySetting("frequencies");
|
applySetting("frequencySettings");
|
||||||
}
|
}
|
||||||
else if (column == COL_NOTES)
|
else if (column == COL_NOTES)
|
||||||
{
|
{
|
||||||
m_settings.m_notes[row] = item->text();
|
m_settings.m_frequencySettings[row].m_notes = item->text();
|
||||||
applySetting("frequencies");
|
applySetting("frequencySettings");
|
||||||
}
|
}
|
||||||
|
else if (column == COL_CHANNEL_BW)
|
||||||
|
{
|
||||||
|
m_settings.m_frequencySettings[row].m_channelBandwidth = item->text();
|
||||||
|
applySetting("frequencySettings");
|
||||||
|
}
|
||||||
|
else if (column == COL_TH)
|
||||||
|
{
|
||||||
|
m_settings.m_frequencySettings[row].m_threshold = item->text();
|
||||||
|
applySetting("frequencySettings");
|
||||||
|
}
|
||||||
|
else if (column == COL_SQ)
|
||||||
|
{
|
||||||
|
m_settings.m_frequencySettings[row].m_squelch = item->text();
|
||||||
|
applySetting("frequencySettings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (column == COL_CHANNEL)
|
||||||
|
{
|
||||||
|
QComboBox *combo = qobject_cast<QComboBox *>(ui->table->cellWidget(row, COL_CHANNEL));
|
||||||
|
m_settings.m_frequencySettings[row].m_channel = combo->currentText();
|
||||||
|
qDebug() << "Setting row" << row << "to" << combo->currentText();
|
||||||
|
applySetting("frequencySettings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,7 +1032,11 @@ void FreqScannerGUI::resizeTable()
|
|||||||
ui->table->setItem(row, COL_ENABLE, new QTableWidgetItem("Enable"));
|
ui->table->setItem(row, COL_ENABLE, new QTableWidgetItem("Enable"));
|
||||||
ui->table->setItem(row, COL_POWER, new QTableWidgetItem("-100.0"));
|
ui->table->setItem(row, COL_POWER, new QTableWidgetItem("-100.0"));
|
||||||
ui->table->setItem(row, COL_ACTIVE_COUNT, new QTableWidgetItem("10000"));
|
ui->table->setItem(row, COL_ACTIVE_COUNT, new QTableWidgetItem("10000"));
|
||||||
ui->table->setItem(row, COL_NOTES, new QTableWidgetItem("Enter some notes"));
|
ui->table->setItem(row, COL_NOTES, new QTableWidgetItem("A channel name"));
|
||||||
|
ui->table->setItem(row, COL_CHANNEL, new QTableWidgetItem("Enter some notes"));
|
||||||
|
ui->table->setItem(row, COL_CHANNEL_BW, new QTableWidgetItem("100000000"));
|
||||||
|
ui->table->setItem(row, COL_TH, new QTableWidgetItem("-100.0"));
|
||||||
|
ui->table->setItem(row, COL_SQ, new QTableWidgetItem("-100.0"));
|
||||||
ui->table->resizeColumnsToContents();
|
ui->table->resizeColumnsToContents();
|
||||||
ui->table->setRowCount(row);
|
ui->table->setRowCount(row);
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ class BasebandSampleSink;
|
|||||||
class FreqScanner;
|
class FreqScanner;
|
||||||
class FreqScannerGUI;
|
class FreqScannerGUI;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
class QComboBox;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class FreqScannerGUI;
|
class FreqScannerGUI;
|
||||||
@ -81,6 +82,8 @@ private:
|
|||||||
|
|
||||||
QMenu *m_menu;
|
QMenu *m_menu;
|
||||||
|
|
||||||
|
QList<FreqScannerSettings::AvailableChannel> m_availableChannels;
|
||||||
|
|
||||||
explicit FreqScannerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
explicit FreqScannerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
||||||
virtual ~FreqScannerGUI();
|
virtual ~FreqScannerGUI();
|
||||||
|
|
||||||
@ -92,9 +95,10 @@ private:
|
|||||||
bool handleMessage(const Message& message);
|
bool handleMessage(const Message& message);
|
||||||
void makeUIConnections();
|
void makeUIConnections();
|
||||||
void updateAbsoluteCenterFrequency();
|
void updateAbsoluteCenterFrequency();
|
||||||
void addRow(qint64 frequency, bool enabled, const QString& notes = "");
|
void addRow(const FreqScannerSettings::FrequencySettings& frequencySettings);
|
||||||
void updateAnnotation(int row);
|
void updateAnnotation(int row);
|
||||||
void updateAnnotations();
|
void updateAnnotations();
|
||||||
|
void updateChannelsCombo(QComboBox *combo, const QList<FreqScannerSettings::AvailableChannel>& channels, const QString& channel, bool empty);
|
||||||
void updateChannelsList(const QList<FreqScannerSettings::AvailableChannel>& channels);
|
void updateChannelsList(const QList<FreqScannerSettings::AvailableChannel>& channels);
|
||||||
void setAllEnabled(bool enable);
|
void setAllEnabled(bool enable);
|
||||||
|
|
||||||
@ -110,7 +114,11 @@ private:
|
|||||||
COL_ENABLE,
|
COL_ENABLE,
|
||||||
COL_POWER,
|
COL_POWER,
|
||||||
COL_ACTIVE_COUNT,
|
COL_ACTIVE_COUNT,
|
||||||
COL_NOTES
|
COL_NOTES,
|
||||||
|
COL_CHANNEL,
|
||||||
|
COL_CHANNEL_BW,
|
||||||
|
COL_TH,
|
||||||
|
COL_SQ
|
||||||
};
|
};
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@ -125,6 +133,7 @@ private slots:
|
|||||||
void on_measurement_currentIndexChanged(int index);
|
void on_measurement_currentIndexChanged(int index);
|
||||||
void on_mode_currentIndexChanged(int index);
|
void on_mode_currentIndexChanged(int index);
|
||||||
void on_table_cellChanged(int row, int column);
|
void on_table_cellChanged(int row, int column);
|
||||||
|
void on_table_channel_currentIndexChanged(int index);
|
||||||
void table_customContextMenuRequested(QPoint pos);
|
void table_customContextMenuRequested(QPoint pos);
|
||||||
void table_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
void table_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
||||||
void table_sectionResized(int logicalIndex, int oldSize, int newSize);
|
void table_sectionResized(int logicalIndex, int oldSize, int newSize);
|
||||||
|
@ -671,6 +671,46 @@
|
|||||||
<string>User notes about this frequency</string>
|
<string>User notes about this frequency</string>
|
||||||
</property>
|
</property>
|
||||||
</column>
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Channel</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Frequency specific channel to tune
|
||||||
|
|
||||||
|
Leave blank for common setting</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Ch BW (Hz)</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Frequency specific channel BW
|
||||||
|
|
||||||
|
Leave blank to use common setting</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>TH (dB)</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Frequency specific threshold in dB
|
||||||
|
|
||||||
|
Leave blank to use common setting</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Sq (dB)</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Frequency specific squelch in dB
|
||||||
|
|
||||||
|
Leave blank for no adjustment</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -783,18 +823,18 @@
|
|||||||
<extends>QToolButton</extends>
|
<extends>QToolButton</extends>
|
||||||
<header>gui/buttonswitch.h</header>
|
<header>gui/buttonswitch.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
|
||||||
<class>RollupContents</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>gui/rollupcontents.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>ValueDialZ</class>
|
<class>ValueDialZ</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
<header>gui/valuedialz.h</header>
|
<header>gui/valuedialz.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>RollupContents</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>gui/rollupcontents.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>deltaFrequency</tabstop>
|
<tabstop>deltaFrequency</tabstop>
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "util/simpleserializer.h"
|
#include "util/simpleserializer.h"
|
||||||
#include "settings/serializable.h"
|
#include "settings/serializable.h"
|
||||||
@ -40,6 +41,7 @@ void FreqScannerSettings::resetToDefaults()
|
|||||||
m_channelFrequencyOffset = 25000;
|
m_channelFrequencyOffset = 25000;
|
||||||
m_threshold = -60.0f;
|
m_threshold = -60.0f;
|
||||||
m_channel = "";
|
m_channel = "";
|
||||||
|
m_frequencySettings = {};
|
||||||
m_scanTime = 0.1f;
|
m_scanTime = 0.1f;
|
||||||
m_retransmitTime = 2.0f;
|
m_retransmitTime = 2.0f;
|
||||||
m_tuneTime = 100;
|
m_tuneTime = 100;
|
||||||
@ -73,9 +75,6 @@ QByteArray FreqScannerSettings::serialize() const
|
|||||||
s.writeS32(2, m_channelBandwidth);
|
s.writeS32(2, m_channelBandwidth);
|
||||||
s.writeS32(3, m_channelFrequencyOffset);
|
s.writeS32(3, m_channelFrequencyOffset);
|
||||||
s.writeFloat(4, m_threshold);
|
s.writeFloat(4, m_threshold);
|
||||||
s.writeList(5, m_notes);
|
|
||||||
s.writeList(6, m_enabled);
|
|
||||||
s.writeList(7, m_frequencies);
|
|
||||||
s.writeString(8, m_channel);
|
s.writeString(8, m_channel);
|
||||||
s.writeFloat(9, m_scanTime);
|
s.writeFloat(9, m_scanTime);
|
||||||
s.writeFloat(10, m_retransmitTime);
|
s.writeFloat(10, m_retransmitTime);
|
||||||
@ -83,6 +82,7 @@ QByteArray FreqScannerSettings::serialize() const
|
|||||||
s.writeS32(12, (int)m_priority);
|
s.writeS32(12, (int)m_priority);
|
||||||
s.writeS32(13, (int)m_measurement);
|
s.writeS32(13, (int)m_measurement);
|
||||||
s.writeS32(14, (int)m_mode);
|
s.writeS32(14, (int)m_mode);
|
||||||
|
s.writeList(15, m_frequencySettings);
|
||||||
|
|
||||||
s.writeList(20, m_columnIndexes);
|
s.writeList(20, m_columnIndexes);
|
||||||
s.writeList(21, m_columnSizes);
|
s.writeList(21, m_columnSizes);
|
||||||
@ -128,22 +128,37 @@ bool FreqScannerSettings::deserialize(const QByteArray& data)
|
|||||||
d.readS32(2, &m_channelBandwidth, 25000);
|
d.readS32(2, &m_channelBandwidth, 25000);
|
||||||
d.readS32(3, &m_channelFrequencyOffset, 25000);
|
d.readS32(3, &m_channelFrequencyOffset, 25000);
|
||||||
d.readFloat(4, &m_threshold, -60.0f);
|
d.readFloat(4, &m_threshold, -60.0f);
|
||||||
d.readList(5, &m_notes);
|
|
||||||
d.readList(6, &m_enabled);
|
|
||||||
d.readList(7, &m_frequencies);
|
|
||||||
d.readString(8, &m_channel);
|
d.readString(8, &m_channel);
|
||||||
while (m_notes.size() < m_frequencies.size()) {
|
|
||||||
m_notes.append("");
|
|
||||||
}
|
|
||||||
while (m_enabled.size() < m_frequencies.size()) {
|
|
||||||
m_enabled.append(true);
|
|
||||||
}
|
|
||||||
d.readFloat(9, &m_scanTime, 0.1f);
|
d.readFloat(9, &m_scanTime, 0.1f);
|
||||||
d.readFloat(10, &m_retransmitTime, 2.0f);
|
d.readFloat(10, &m_retransmitTime, 2.0f);
|
||||||
d.readS32(11, &m_tuneTime, 100);
|
d.readS32(11, &m_tuneTime, 100);
|
||||||
d.readS32(12, (int*)&m_priority, (int)MAX_POWER);
|
d.readS32(12, (int*)&m_priority, (int)MAX_POWER);
|
||||||
d.readS32(13, (int*)&m_measurement, (int)PEAK);
|
d.readS32(13, (int*)&m_measurement, (int)PEAK);
|
||||||
d.readS32(14, (int*)&m_mode, (int)CONTINUOUS);
|
d.readS32(14, (int*)&m_mode, (int)CONTINUOUS);
|
||||||
|
d.readList(15, &m_frequencySettings);
|
||||||
|
if (m_frequencySettings.size() == 0)
|
||||||
|
{
|
||||||
|
// Try reading old settings
|
||||||
|
QList<bool> enabled;
|
||||||
|
QList<qint64> frequencies;
|
||||||
|
|
||||||
|
d.readList(6, &enabled);
|
||||||
|
d.readList(7, &frequencies);
|
||||||
|
if (frequencies.size() > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < frequencies.size(); i++)
|
||||||
|
{
|
||||||
|
FrequencySettings frequencySettings;
|
||||||
|
frequencySettings.m_frequency = frequencies[i];
|
||||||
|
if (i < enabled.size()) {
|
||||||
|
frequencySettings.m_enabled = enabled[i];
|
||||||
|
} else {
|
||||||
|
frequencySettings.m_enabled = true;
|
||||||
|
}
|
||||||
|
m_frequencySettings.append(frequencySettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d.readList(20, &m_columnIndexes);
|
d.readList(20, &m_columnIndexes);
|
||||||
d.readList(21, &m_columnSizes);
|
d.readList(21, &m_columnSizes);
|
||||||
@ -200,10 +215,8 @@ void FreqScannerSettings::applySettings(const QStringList& settingsKeys, const F
|
|||||||
if (settingsKeys.contains("threshold")) {
|
if (settingsKeys.contains("threshold")) {
|
||||||
m_threshold = settings.m_threshold;
|
m_threshold = settings.m_threshold;
|
||||||
}
|
}
|
||||||
if (settingsKeys.contains("frequencies")) {
|
if (settingsKeys.contains("frequencySettings")) {
|
||||||
m_frequencies = settings.m_frequencies;
|
m_frequencySettings = settings.m_frequencySettings;
|
||||||
m_enabled = settings.m_enabled;
|
|
||||||
m_notes = settings.m_notes;
|
|
||||||
}
|
}
|
||||||
if (settingsKeys.contains("channel")) {
|
if (settingsKeys.contains("channel")) {
|
||||||
m_channel = settings.m_channel;
|
m_channel = settings.m_channel;
|
||||||
@ -280,13 +293,13 @@ QString FreqScannerSettings::getDebugString(const QStringList& settingsKeys, boo
|
|||||||
if (settingsKeys.contains("threshold") || force) {
|
if (settingsKeys.contains("threshold") || force) {
|
||||||
ostr << " m_threshold: " << m_threshold;
|
ostr << " m_threshold: " << m_threshold;
|
||||||
}
|
}
|
||||||
if (settingsKeys.contains("frequencies") || force)
|
if (settingsKeys.contains("frequencySettings") || force)
|
||||||
{
|
{
|
||||||
QStringList s;
|
QStringList s;
|
||||||
for (auto f : m_frequencies) {
|
for (auto f : m_frequencySettings) {
|
||||||
s.append(QString::number(f));
|
s.append(QString::number(f.m_frequency));
|
||||||
}
|
}
|
||||||
ostr << " m_frequencies: " << s.join(",").toStdString();
|
ostr << " m_frequencySettings: " << s.join(",").toStdString();
|
||||||
}
|
}
|
||||||
if (settingsKeys.contains("channel") || force) {
|
if (settingsKeys.contains("channel") || force) {
|
||||||
ostr << " m_channel: " << m_channel.toStdString();
|
ostr << " m_channel: " << m_channel.toStdString();
|
||||||
@ -348,3 +361,105 @@ QString FreqScannerSettings::getDebugString(const QStringList& settingsKeys, boo
|
|||||||
|
|
||||||
return QString(ostr.str().c_str());
|
return QString(ostr.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QByteArray FreqScannerSettings::FrequencySettings::serialize() const
|
||||||
|
{
|
||||||
|
SimpleSerializer s(1);
|
||||||
|
|
||||||
|
s.writeS64(1, m_frequency);
|
||||||
|
s.writeBool(2, m_enabled);
|
||||||
|
s.writeString(3, m_notes);
|
||||||
|
s.writeString(4, m_threshold);
|
||||||
|
s.writeString(5, m_channel);
|
||||||
|
s.writeString(6, m_channelBandwidth);
|
||||||
|
s.writeString(7, m_squelch);
|
||||||
|
|
||||||
|
return s.final();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FreqScannerSettings::FrequencySettings::deserialize(const QByteArray& data)
|
||||||
|
{
|
||||||
|
SimpleDeserializer d(data);
|
||||||
|
|
||||||
|
if (!d.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.getVersion() == 1)
|
||||||
|
{
|
||||||
|
QByteArray blob;
|
||||||
|
|
||||||
|
d.readS64(1, &m_frequency);
|
||||||
|
d.readBool(2, &m_enabled);
|
||||||
|
d.readString(3, &m_notes);
|
||||||
|
d.readString(4, &m_threshold);
|
||||||
|
d.readString(5, &m_channel);
|
||||||
|
d.readString(6, &m_channelBandwidth);
|
||||||
|
d.readString(7, &m_squelch);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator<<(QDataStream& out, const FreqScannerSettings::FrequencySettings& settings)
|
||||||
|
{
|
||||||
|
out << settings.serialize();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream& operator>>(QDataStream& in, FreqScannerSettings::FrequencySettings& settings)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
in >> data;
|
||||||
|
settings.deserialize(data);
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
Real FreqScannerSettings::getThreshold(FreqScannerSettings::FrequencySettings *frequencySettings) const
|
||||||
|
{
|
||||||
|
Real threshold = m_threshold;
|
||||||
|
if (!frequencySettings->m_threshold.isEmpty())
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
Real perFrequencyThreshold = frequencySettings->m_threshold.toFloat(&ok);
|
||||||
|
if (ok) {
|
||||||
|
threshold = perFrequencyThreshold;
|
||||||
|
} else {
|
||||||
|
qDebug() << "FreqScannerSettings::getThreshold: Failed to parse" << frequencySettings->m_threshold << "as a float";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FreqScannerSettings::getChannelBandwidth(FreqScannerSettings::FrequencySettings *frequencySettings) const
|
||||||
|
{
|
||||||
|
int channelBandwidth = m_channelBandwidth;
|
||||||
|
if (!frequencySettings->m_channelBandwidth.isEmpty())
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
Real perFrequencyChannelBandwidth = frequencySettings->m_channelBandwidth.toInt(&ok);
|
||||||
|
if (ok) {
|
||||||
|
channelBandwidth = perFrequencyChannelBandwidth;
|
||||||
|
} else {
|
||||||
|
qDebug() << "FreqScannerSettings::getChannelBandwidth: Failed to parse" << frequencySettings->m_channelBandwidth << "as an int";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return channelBandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
FreqScannerSettings::FrequencySettings *FreqScannerSettings::getFrequencySettings(qint64 frequency)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_frequencySettings.size(); i++)
|
||||||
|
{
|
||||||
|
if (frequency == m_frequencySettings[i].m_frequency) {
|
||||||
|
return &this->m_frequencySettings[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class Serializable;
|
|||||||
class ChannelAPI;
|
class ChannelAPI;
|
||||||
|
|
||||||
// Number of columns in the table
|
// Number of columns in the table
|
||||||
#define FREQSCANNER_COLUMNS 6
|
#define FREQSCANNER_COLUMNS 10
|
||||||
|
|
||||||
struct FreqScannerSettings
|
struct FreqScannerSettings
|
||||||
{
|
{
|
||||||
@ -41,14 +41,25 @@ struct FreqScannerSettings
|
|||||||
AvailableChannel& operator=(const AvailableChannel&) = default;
|
AvailableChannel& operator=(const AvailableChannel&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FrequencySettings {
|
||||||
|
qint64 m_frequency;
|
||||||
|
bool m_enabled;
|
||||||
|
QString m_notes;
|
||||||
|
QString m_threshold; // QStrings used, as we allow "" for no setting
|
||||||
|
QString m_channel;
|
||||||
|
QString m_channelBandwidth;
|
||||||
|
QString m_squelch;
|
||||||
|
|
||||||
|
QByteArray serialize() const;
|
||||||
|
bool deserialize(const QByteArray& data);
|
||||||
|
};
|
||||||
|
|
||||||
qint32 m_inputFrequencyOffset; //!< Not modifable in GUI
|
qint32 m_inputFrequencyOffset; //!< Not modifable in GUI
|
||||||
qint32 m_channelBandwidth; //!< Channel bandwidth
|
qint32 m_channelBandwidth; //!< Channel bandwidth
|
||||||
qint32 m_channelFrequencyOffset;//!< Minium DC offset of tuned channel
|
qint32 m_channelFrequencyOffset;//!< Minium DC offset of tuned channel
|
||||||
Real m_threshold; //!< Power threshold in dB
|
Real m_threshold; //!< Power threshold in dB
|
||||||
QList<qint64> m_frequencies; //!< Frequencies to scan
|
|
||||||
QList<bool> m_enabled; //!< Whether corresponding frequency is enabled
|
|
||||||
QList<QString> m_notes; //!< User editable notes about this frequency
|
|
||||||
QString m_channel; //!< Channel (E.g: R1:4) to tune to active frequency
|
QString m_channel; //!< Channel (E.g: R1:4) to tune to active frequency
|
||||||
|
QList<FrequencySettings> m_frequencySettings; //!< Frequencies to scan and corresponding settings
|
||||||
float m_scanTime; //!< In seconds
|
float m_scanTime; //!< In seconds
|
||||||
float m_retransmitTime; //!< In seconds
|
float m_retransmitTime; //!< In seconds
|
||||||
int m_tuneTime; //!< In milliseconds
|
int m_tuneTime; //!< In milliseconds
|
||||||
@ -92,6 +103,9 @@ struct FreqScannerSettings
|
|||||||
bool deserialize(const QByteArray& data);
|
bool deserialize(const QByteArray& data);
|
||||||
void applySettings(const QStringList& settingsKeys, const FreqScannerSettings& settings);
|
void applySettings(const QStringList& settingsKeys, const FreqScannerSettings& settings);
|
||||||
QString getDebugString(const QStringList& settingsKeys, bool force = false) const;
|
QString getDebugString(const QStringList& settingsKeys, bool force = false) const;
|
||||||
|
Real getThreshold(FreqScannerSettings::FrequencySettings *frequencySettings) const;
|
||||||
|
int getChannelBandwidth(FreqScannerSettings::FrequencySettings *frequencySettings) const;
|
||||||
|
FreqScannerSettings::FrequencySettings *getFrequencySettings(qint64 frequency);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCLUDE_FREQSCANNERSETTINGS_H */
|
#endif /* INCLUDE_FREQSCANNERSETTINGS_H */
|
||||||
|
@ -107,11 +107,11 @@ void FreqScannerSink::processOneSample(Complex &ci)
|
|||||||
FreqScanner::MsgScanResult* msg = FreqScanner::MsgScanResult::create(m_fftStartTime);
|
FreqScanner::MsgScanResult* msg = FreqScanner::MsgScanResult::create(m_fftStartTime);
|
||||||
QList<FreqScanner::MsgScanResult::ScanResult>& results = msg->getScanResults();
|
QList<FreqScanner::MsgScanResult::ScanResult>& results = msg->getScanResults();
|
||||||
|
|
||||||
for (int i = 0; i < m_settings.m_frequencies.size(); i++)
|
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_settings.m_enabled[i])
|
if (m_settings.m_frequencySettings[i].m_enabled)
|
||||||
{
|
{
|
||||||
qint64 frequency = m_settings.m_frequencies[i];
|
qint64 frequency = m_settings.m_frequencySettings[i].m_frequency;
|
||||||
qint64 startFrequency = m_centerFrequency - m_scannerSampleRate / 2;
|
qint64 startFrequency = m_centerFrequency - m_scannerSampleRate / 2;
|
||||||
qint64 diff = frequency - startFrequency;
|
qint64 diff = frequency - startFrequency;
|
||||||
float binBW = m_scannerSampleRate / (float)m_fftSize;
|
float binBW = m_scannerSampleRate / (float)m_fftSize;
|
||||||
@ -120,13 +120,24 @@ void FreqScannerSink::processOneSample(Complex &ci)
|
|||||||
if ((diff < m_scannerSampleRate * 0.875f) && (diff >= m_scannerSampleRate * 0.125f))
|
if ((diff < m_scannerSampleRate * 0.875f) && (diff >= m_scannerSampleRate * 0.125f))
|
||||||
{
|
{
|
||||||
int bin = std::round(diff / binBW);
|
int bin = std::round(diff / binBW);
|
||||||
|
int channelBins;
|
||||||
|
|
||||||
|
if (m_settings.m_frequencySettings[i].m_channelBandwidth.isEmpty())
|
||||||
|
{
|
||||||
|
channelBins = m_binsPerChannel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int channelBW = m_settings.getChannelBandwidth(&m_settings.m_frequencySettings[i]);
|
||||||
|
channelBins = m_fftSize / (m_scannerSampleRate / (float)channelBW);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate power at that frequency
|
// Calculate power at that frequency
|
||||||
Real power;
|
Real power;
|
||||||
if (m_settings.m_measurement == FreqScannerSettings::PEAK) {
|
if (m_settings.m_measurement == FreqScannerSettings::PEAK) {
|
||||||
power = peakPower(bin);
|
power = peakPower(bin, channelBins);
|
||||||
} else {
|
} else {
|
||||||
power = totalPower(bin);
|
power = totalPower(bin, channelBins);
|
||||||
}
|
}
|
||||||
//qDebug() << "startFrequency:" << startFrequency << "m_scannerSampleRate:" << m_scannerSampleRate << "m_centerFrequency:" << m_centerFrequency << "frequency" << frequency << "bin" << bin << "power" << power;
|
//qDebug() << "startFrequency:" << startFrequency << "m_scannerSampleRate:" << m_scannerSampleRate << "m_centerFrequency:" << m_centerFrequency << "frequency" << frequency << "bin" << bin << "power" << power;
|
||||||
FreqScanner::MsgScanResult::ScanResult result = {frequency, power};
|
FreqScanner::MsgScanResult::ScanResult result = {frequency, power};
|
||||||
@ -144,13 +155,13 @@ void FreqScannerSink::processOneSample(Complex &ci)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate total power in a channel containing the specified bin (i.e. sums adjacent bins in the same channel)
|
// Calculate total power in a channel containing the specified bin (i.e. sums adjacent bins in the same channel)
|
||||||
Real FreqScannerSink::totalPower(int bin) const
|
Real FreqScannerSink::totalPower(int bin, int channelBins) const
|
||||||
{
|
{
|
||||||
// Skip bin between halfway between channels
|
// Skip bin between halfway between channels
|
||||||
// Then skip first and last bins, to avoid spectral leakage (particularly at DC)
|
// Then skip first and last bins, to avoid spectral leakage (particularly at DC)
|
||||||
int startBin = bin - m_binsPerChannel / 2 + 1 + 1;
|
int startBin = bin - channelBins / 2 + 1 + 1;
|
||||||
Real magSqSum = 0.0f;
|
Real magSqSum = 0.0f;
|
||||||
for (int i = 0; i < m_binsPerChannel - 2 - 1; i++) {
|
for (int i = 0; i < channelBins - 2 - 1; i++) {
|
||||||
int idx = startBin + i;
|
int idx = startBin + i;
|
||||||
if ((idx < 0) || (idx >= m_fftSize)) {
|
if ((idx < 0) || (idx >= m_fftSize)) {
|
||||||
continue;
|
continue;
|
||||||
@ -162,13 +173,13 @@ Real FreqScannerSink::totalPower(int bin) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate peak power in a channel containing the specified bin
|
// Calculate peak power in a channel containing the specified bin
|
||||||
Real FreqScannerSink::peakPower(int bin) const
|
Real FreqScannerSink::peakPower(int bin, int channelBins) const
|
||||||
{
|
{
|
||||||
// Skip bin between halfway between channels
|
// Skip bin between halfway between channels
|
||||||
// Then skip first and last bins, to avoid spectral leakage (particularly at DC)
|
// Then skip first and last bins, to avoid spectral leakage (particularly at DC)
|
||||||
int startBin = bin - m_binsPerChannel/2 + 1 + 1;
|
int startBin = bin - channelBins/2 + 1 + 1;
|
||||||
Real maxMagSq = std::numeric_limits<Real>::min();
|
Real maxMagSq = std::numeric_limits<Real>::min();
|
||||||
for (int i = 0; i < m_binsPerChannel - 2 - 1; i++)
|
for (int i = 0; i < channelBins - 2 - 1; i++)
|
||||||
{
|
{
|
||||||
int idx = startBin + i;
|
int idx = startBin + i;
|
||||||
if ((idx < 0) || (idx >= m_fftSize)) {
|
if ((idx < 0) || (idx >= m_fftSize)) {
|
||||||
|
@ -79,8 +79,8 @@ private:
|
|||||||
|
|
||||||
void processOneSample(Complex &ci);
|
void processOneSample(Complex &ci);
|
||||||
MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; }
|
MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; }
|
||||||
Real totalPower(int bin) const;
|
Real totalPower(int bin, int channelBins) const;
|
||||||
Real peakPower(int bin) const;
|
Real peakPower(int bin, int channelBins) const;
|
||||||
Real magSq(int bin) const;
|
Real magSq(int bin) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,6 +97,10 @@ The frequency table contains the list of frequencies to be scanned, along with r
|
|||||||
- Power (dB): Displays the measured power in decibels from the last scan. The cell will have a green background if the power was above the threshold (4).
|
- Power (dB): Displays the measured power in decibels from the last scan. The cell will have a green background if the power was above the threshold (4).
|
||||||
- Active Count: Displays the number of scans in which the power for this frequency was above the threshold (4). This allows you to see which frequencies are commonly in use.
|
- Active Count: Displays the number of scans in which the power for this frequency was above the threshold (4). This allows you to see which frequencies are commonly in use.
|
||||||
- Notes: Available for user-entry of notes/information about this frequency.
|
- Notes: Available for user-entry of notes/information about this frequency.
|
||||||
|
- Channel: Specifies the channel that should be tuned when this frequency is active. If blank, the common Channel setting (1) is used.
|
||||||
|
- Ch Bw (Hz): Specifies the channel bandwidth in Hertz. If blank, the common Channel Bandwidth setting (8) is used.
|
||||||
|
- TH (dB): Specifies the power threshold in dB that determines whether this frequency is active or not. If blank, the common Threshold setting (4) is used.
|
||||||
|
- Sq (dB): Specifies a squelch level in dB that will be applied to the Channel when active. If blank, the squelch level will not be changed.
|
||||||
|
|
||||||
When an active frequency is found after a scan, the corresponding row in the table will be selected.
|
When an active frequency is found after a scan, the corresponding row in the table will be selected.
|
||||||
|
|
||||||
|
@ -1293,6 +1293,53 @@ bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, double value)
|
||||||
|
{
|
||||||
|
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
|
||||||
|
QString errorResponse;
|
||||||
|
int httpRC;
|
||||||
|
ChannelAPI *channel;
|
||||||
|
|
||||||
|
if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel))
|
||||||
|
{
|
||||||
|
// Patch settings
|
||||||
|
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
|
||||||
|
double oldValue;
|
||||||
|
if (WebAPIUtils::getSubObjectDouble(*jsonObj, setting, oldValue))
|
||||||
|
{
|
||||||
|
WebAPIUtils::setSubObjectDouble(*jsonObj, setting, value);
|
||||||
|
QStringList channelSettingsKeys;
|
||||||
|
channelSettingsKeys.append(setting);
|
||||||
|
channelSettingsResponse.init();
|
||||||
|
channelSettingsResponse.fromJsonObject(*jsonObj);
|
||||||
|
SWGSDRangel::SWGErrorResponse errorResponse2;
|
||||||
|
|
||||||
|
httpRC = channel->webapiSettingsPutPatch(false, channelSettingsKeys, channelSettingsResponse, *errorResponse2.getMessage());
|
||||||
|
|
||||||
|
if (httpRC/100 == 2)
|
||||||
|
{
|
||||||
|
qDebug("ChannelWebAPIUtils::patchChannelSetting: set feature setting %s to %f OK", qPrintable(setting), value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning("ChannelWebAPIUtils::patchChannelSetting: set feature setting %s to %f error %d: %s",
|
||||||
|
qPrintable(setting), value, httpRC, qPrintable(*errorResponse2.getMessage()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning("ChannelWebAPIUtils::patchChannelSetting: no key %s in feature settings", qPrintable(setting));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, const QJsonArray& value)
|
bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsigned int channelIndex, const QString &setting, const QJsonArray& value)
|
||||||
{
|
{
|
||||||
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
|
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
|
||||||
|
@ -73,6 +73,7 @@ public:
|
|||||||
static bool patchDeviceSetting(unsigned int deviceIndex, const QString &setting, int value);
|
static bool patchDeviceSetting(unsigned int deviceIndex, const QString &setting, int value);
|
||||||
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, const QString &value);
|
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, const QString &value);
|
||||||
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double value);
|
static bool patchFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double value);
|
||||||
|
static bool patchChannelSetting(unsigned int deviceSetIndex, unsigned int channeIndex, const QString &setting, double value);
|
||||||
static bool patchChannelSetting(unsigned int deviceSetIndex, unsigned int channeIndex, const QString &setting, const QJsonArray& value);
|
static bool patchChannelSetting(unsigned int deviceSetIndex, unsigned int channeIndex, const QString &setting, const QJsonArray& value);
|
||||||
static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, int &value);
|
static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, int &value);
|
||||||
static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double &value);
|
static bool getFeatureSetting(unsigned int featureSetIndex, unsigned int featureIndex, const QString &setting, double &value);
|
||||||
|
@ -105,7 +105,7 @@ public:
|
|||||||
bool readBlob(quint32 id, QByteArray* result, const QByteArray& def = QByteArray()) const;
|
bool readBlob(quint32 id, QByteArray* result, const QByteArray& def = QByteArray()) const;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool readList(quint32 id, QList<T>* result)
|
bool readList(quint32 id, QList<T>* result, const QList<T>& def = {})
|
||||||
{
|
{
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
bool ok = readBlob(id, &data);
|
bool ok = readBlob(id, &data);
|
||||||
@ -115,10 +115,14 @@ public:
|
|||||||
(*stream) >> *result;
|
(*stream) >> *result;
|
||||||
delete stream;
|
delete stream;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*result = def;
|
||||||
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
template<typename TK, typename TV>
|
template<typename TK, typename TV>
|
||||||
bool readHash(quint32 id, QHash<TK,TV>* result)
|
bool readHash(quint32 id, QHash<TK,TV>* result, const QHash<TK,TV>& def = {})
|
||||||
{
|
{
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
bool ok = readBlob(id, &data);
|
bool ok = readBlob(id, &data);
|
||||||
@ -128,6 +132,10 @@ public:
|
|||||||
(*stream) >> *result;
|
(*stream) >> *result;
|
||||||
delete stream;
|
delete stream;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*result = def;
|
||||||
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ set(sdrgui_SOURCES
|
|||||||
gui/graphicsviewzoom.cpp
|
gui/graphicsviewzoom.cpp
|
||||||
gui/httpdownloadmanagergui.cpp
|
gui/httpdownloadmanagergui.cpp
|
||||||
gui/indicator.cpp
|
gui/indicator.cpp
|
||||||
|
gui/int64delegate.cpp
|
||||||
|
gui/int64validator.cpp
|
||||||
gui/levelmeter.cpp
|
gui/levelmeter.cpp
|
||||||
gui/loggingdialog.cpp
|
gui/loggingdialog.cpp
|
||||||
gui/logslider.cpp
|
gui/logslider.cpp
|
||||||
@ -186,6 +188,8 @@ set(sdrgui_HEADERS
|
|||||||
gui/graphicsviewzoom.h
|
gui/graphicsviewzoom.h
|
||||||
gui/httpdownloadmanagergui.h
|
gui/httpdownloadmanagergui.h
|
||||||
gui/indicator.h
|
gui/indicator.h
|
||||||
|
gui/int64delegate.h
|
||||||
|
gui/int64validator.h
|
||||||
gui/levelmeter.h
|
gui/levelmeter.h
|
||||||
gui/loggingdialog.h
|
gui/loggingdialog.h
|
||||||
gui/logslider.h
|
gui/logslider.h
|
||||||
|
@ -18,10 +18,40 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QDoubleValidator>
|
||||||
|
|
||||||
#include "decimaldelegate.h"
|
#include "decimaldelegate.h"
|
||||||
|
|
||||||
|
// Allow "" or double
|
||||||
|
class DoubleOrEmptyValidator : public QDoubleValidator {
|
||||||
|
public:
|
||||||
|
DoubleOrEmptyValidator(double bottom, double top, int decimals, QObject *parent = nullptr) :
|
||||||
|
QDoubleValidator(bottom, top, decimals, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QValidator::State validate(QString& input, int &pos) const
|
||||||
|
{
|
||||||
|
if (input == "") {
|
||||||
|
return QValidator::Acceptable;
|
||||||
|
} else {
|
||||||
|
return QDoubleValidator::validate(input, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
DecimalDelegate::DecimalDelegate(int precision) :
|
DecimalDelegate::DecimalDelegate(int precision) :
|
||||||
m_precision(precision)
|
m_precision(precision),
|
||||||
|
m_min(-std::numeric_limits<double>::max()),
|
||||||
|
m_max(std::numeric_limits<double>::max())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DecimalDelegate::DecimalDelegate(int precision, double min, double max) :
|
||||||
|
m_precision(precision),
|
||||||
|
m_min(min),
|
||||||
|
m_max(max)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,3 +66,22 @@ QString DecimalDelegate::displayText(const QVariant &value, const QLocale &local
|
|||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget *DecimalDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
(void) option;
|
||||||
|
(void) index;
|
||||||
|
|
||||||
|
QLineEdit* editor = new QLineEdit(parent);
|
||||||
|
DoubleOrEmptyValidator *validator = new DoubleOrEmptyValidator(m_min, m_max, m_precision);
|
||||||
|
validator->setBottom(m_min);
|
||||||
|
validator->setTop(m_max);
|
||||||
|
editor->setValidator(validator);
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecimalDelegate::setRange(double min, double max)
|
||||||
|
{
|
||||||
|
m_min = min;
|
||||||
|
m_max = max;
|
||||||
|
}
|
||||||
|
@ -26,17 +26,23 @@
|
|||||||
#include "export.h"
|
#include "export.h"
|
||||||
|
|
||||||
// Deligate for table to control precision used to display floating point values - also supports strings
|
// Deligate for table to control precision used to display floating point values - also supports strings
|
||||||
|
// Min and max values are constraints for editing
|
||||||
class SDRGUI_API DecimalDelegate : public QStyledItemDelegate {
|
class SDRGUI_API DecimalDelegate : public QStyledItemDelegate {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DecimalDelegate(int precision = 2);
|
DecimalDelegate(int precision = 2);
|
||||||
|
DecimalDelegate(int precision, double min, double max);
|
||||||
|
|
||||||
virtual QString displayText(const QVariant &value, const QLocale &locale) const override;
|
virtual QString displayText(const QVariant &value, const QLocale &locale) const override;
|
||||||
|
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
int getPrecision() const { return m_precision; }
|
int getPrecision() const { return m_precision; }
|
||||||
void setPrecision(int precision) { m_precision = precision; }
|
void setPrecision(int precision) { m_precision = precision; }
|
||||||
|
void setRange(double min, double max);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_precision;
|
int m_precision;
|
||||||
|
double m_min;
|
||||||
|
double m_max;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
|
||||||
#include "frequencydelegate.h"
|
#include "frequencydelegate.h"
|
||||||
|
#include "int64validator.h"
|
||||||
|
|
||||||
FrequencyDelegate::FrequencyDelegate(const QString& units, int precision, bool group) :
|
FrequencyDelegate::FrequencyDelegate(const QString& units, int precision, bool group) :
|
||||||
m_units(units),
|
m_units(units),
|
||||||
@ -112,13 +113,14 @@ QString FrequencyDelegate::displayText(const QVariant &value, const QLocale &loc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QWidget* FrequencyDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
QWidget* FrequencyDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
(void) option;
|
(void) option;
|
||||||
(void) index;
|
(void) index;
|
||||||
|
|
||||||
QLineEdit* editor = new QLineEdit(parent);
|
QLineEdit* editor = new QLineEdit(parent);
|
||||||
QIntValidator* validator = new QIntValidator();
|
Int64Validator* validator = new Int64Validator();
|
||||||
validator->setBottom(0);
|
validator->setBottom(0);
|
||||||
editor->setValidator(validator);
|
editor->setValidator(validator);
|
||||||
return editor;
|
return editor;
|
||||||
|
59
sdrgui/gui/int64delegate.cpp
Normal file
59
sdrgui/gui/int64delegate.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
#include "int64delegate.h"
|
||||||
|
#include "int64validator.h"
|
||||||
|
|
||||||
|
Int64Delegate::Int64Delegate() :
|
||||||
|
m_min(-std::numeric_limits<qint64>::max()),
|
||||||
|
m_max(std::numeric_limits<qint64>::max())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64Delegate::Int64Delegate(qint64 min, qint64 max) :
|
||||||
|
m_min(min),
|
||||||
|
m_max(max)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Int64Delegate::displayText(const QVariant &value, const QLocale &locale) const
|
||||||
|
{
|
||||||
|
(void) locale;
|
||||||
|
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *Int64Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
(void) option;
|
||||||
|
(void) index;
|
||||||
|
|
||||||
|
QLineEdit* editor = new QLineEdit(parent);
|
||||||
|
Int64Validator* validator = new Int64Validator();
|
||||||
|
validator->setBottom(m_min);
|
||||||
|
validator->setTop(m_max);
|
||||||
|
editor->setValidator(validator);
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Int64Delegate::setRange(qint64 min, qint64 max)
|
||||||
|
{
|
||||||
|
m_min = min;
|
||||||
|
m_max = max;
|
||||||
|
}
|
46
sdrgui/gui/int64delegate.h
Normal file
46
sdrgui/gui/int64delegate.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SDRGUI_GUI_INT64DELGATE_H
|
||||||
|
#define SDRGUI_GUI_INT64DELGATE_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
#include "export.h"
|
||||||
|
|
||||||
|
// Delegate for table to display a qint64 with input range validation
|
||||||
|
// Also supports "" as a value
|
||||||
|
class SDRGUI_API Int64Delegate : public QStyledItemDelegate {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Int64Delegate();
|
||||||
|
Int64Delegate(qint64 min, qint64 max);
|
||||||
|
virtual QString displayText(const QVariant &value, const QLocale &locale) const override;
|
||||||
|
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
void setMin(qint64 min) { m_min = min; }
|
||||||
|
void setMax(qint64 max) { m_max = max; }
|
||||||
|
void setRange(qint64 min, qint64 max);
|
||||||
|
qint64 min() const { return m_min; }
|
||||||
|
qint64 max() const { return m_max; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
qint64 m_min;
|
||||||
|
qint64 m_max;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SDRGUI_GUI_INT64DELGATE_H
|
47
sdrgui/gui/int64validator.cpp
Normal file
47
sdrgui/gui/int64validator.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "int64validator.h"
|
||||||
|
|
||||||
|
QValidator::State Int64Validator::validate(QString& input, int &pos) const
|
||||||
|
{
|
||||||
|
if (input == "") {
|
||||||
|
return QValidator::Acceptable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_bottom < 0) && (input == "-")) {
|
||||||
|
return QValidator::Intermediate;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegularExpression re("-?\\d+");
|
||||||
|
QRegularExpressionMatch match = re.match(input);
|
||||||
|
if (match.hasMatch())
|
||||||
|
{
|
||||||
|
qint64 value = input.toLongLong();
|
||||||
|
if (value < m_bottom) {
|
||||||
|
return QValidator::Invalid;
|
||||||
|
}
|
||||||
|
if (value > m_top) {
|
||||||
|
return QValidator::Invalid;
|
||||||
|
}
|
||||||
|
return QValidator::Acceptable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QValidator::Invalid;
|
||||||
|
}
|
||||||
|
}
|
75
sdrgui/gui/int64validator.h
Normal file
75
sdrgui/gui/int64validator.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com> //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <QValidator>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
// Like QIntValidator but for qint64
|
||||||
|
class Int64Validator : public QValidator
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Int64Validator(QObject *parent = nullptr) :
|
||||||
|
QValidator(parent),
|
||||||
|
m_bottom(-std::numeric_limits<qint64>::max()),
|
||||||
|
m_top(std::numeric_limits<qint64>::max())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64Validator(qint64 bottom, qint64 top, QObject *parent = nullptr) :
|
||||||
|
QValidator(parent),
|
||||||
|
m_bottom(bottom),
|
||||||
|
m_top(top)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBottom(qint64 bottom)
|
||||||
|
{
|
||||||
|
m_bottom = bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTop(qint64 top)
|
||||||
|
{
|
||||||
|
m_top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRange(qint64 bottom, qint64 top)
|
||||||
|
{
|
||||||
|
m_bottom = bottom;
|
||||||
|
m_top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 bottom() const
|
||||||
|
{
|
||||||
|
return m_bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 top() const
|
||||||
|
{
|
||||||
|
return m_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
QValidator::State validate(QString& input, int &pos) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
qint64 m_bottom;
|
||||||
|
qint64 m_top;
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user