wfview/receiverwidget.cpp

2710 wiersze
100 KiB
C++
Czysty Zwykły widok Historia

2025-01-06 23:10:11 +00:00
#include "receiverwidget.h"
2023-06-01 16:57:44 +00:00
#include "logcategories.h"
2023-06-05 08:27:37 +00:00
#include "rigidentities.h"
2023-06-01 16:57:44 +00:00
2025-01-06 23:10:11 +00:00
receiverWidget::receiverWidget(bool scope, uchar receiver, uchar vfo, QWidget *parent)
2024-06-10 22:58:33 +00:00
: QGroupBox{parent}, receiver(receiver), numVFO(vfo)
2023-06-01 16:57:44 +00:00
{
// Not sure if this should actually be used?
Q_UNUSED(scope)
2023-06-01 16:57:44 +00:00
2023-06-05 08:27:37 +00:00
QMutexLocker locker(&mutex);
2023-06-08 07:20:50 +00:00
this->setObjectName("Spectrum Scope");
2023-06-05 08:27:37 +00:00
this->setTitle("Band");
2023-09-25 13:55:27 +00:00
this->defaultStyleSheet = this->styleSheet();
2023-06-05 08:27:37 +00:00
queue = cachingQueue::getInstance();
2024-10-24 12:08:15 +00:00
rigCaps = queue->getRigCaps();
2024-12-31 18:38:43 +00:00
2023-09-24 23:11:37 +00:00
mainLayout = new QHBoxLayout(this);
2023-09-25 13:55:27 +00:00
layout = new QVBoxLayout();
2023-09-24 23:11:37 +00:00
mainLayout->addLayout(layout);
2023-06-01 16:57:44 +00:00
splitter = new QSplitter(this);
layout->addWidget(splitter);
splitter->setOrientation(Qt::Vertical);
originalParent = parent;
2023-06-01 16:57:44 +00:00
2023-09-26 17:46:04 +00:00
displayLayout = new QHBoxLayout();
2024-12-31 18:38:43 +00:00
vfoSelectButton=new QPushButton(tr("VFO A"),this);
vfoSelectButton->setHidden(true);
vfoSelectButton->setCheckable(true);
vfoSelectButton->setFocusPolicy(Qt::NoFocus);
connect(vfoSelectButton, &QPushButton::clicked, this, [=](bool en) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,false);
queue->add(priorityImmediate,queueItem(funcSelectVFO,QVariant::fromValue<bool>(en),false,t.receiver));
queue->add(priorityHighest,t.freqFunc,false,t.receiver);
queue->add(priorityHighest,t.modeFunc,false,t.receiver);
t = queue->getVfoCommand(vfoB,receiver,false);
queue->add(priorityHighest,t.freqFunc,false,t.receiver);
queue->add(priorityHighest,t.modeFunc,false,t.receiver);
2024-12-31 18:38:43 +00:00
if (en)
vfoSelectButton->setText(tr("VFO B"));
else
vfoSelectButton->setText(tr("VFO A"));
selectedVFO = uchar(en);
});
vfoSwapButton=new QPushButton(tr("A<>B"),this);
vfoSwapButton->setHidden(true);
vfoSwapButton->setFocusPolicy(Qt::NoFocus);
connect(vfoSwapButton, &QPushButton::clicked, this, [=]() {
vfoSwap();
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,false);
queue->add(priorityHighest,t.modeFunc,false,t.receiver);
queue->add(priorityHighest,t.freqFunc,false,t.receiver);
2024-12-31 18:38:43 +00:00
});
vfoEqualsButton=new QPushButton(tr("A=B"),this);
vfoEqualsButton->setHidden(true);
vfoEqualsButton->setFocusPolicy(Qt::NoFocus);
connect(vfoEqualsButton, &QPushButton::clicked, this, [=]() {
vfoCommandType t = queue->getVfoCommand(vfoB,receiver,false);
queue->add(priorityImmediate,funcVFOEqualAB,false,0);
queue->add(priorityHighest,t.modeFunc,false,t.receiver);
queue->add(priorityHighest,t.freqFunc,false,t.receiver);
2024-12-31 18:38:43 +00:00
});
vfoMemoryButton=new QPushButton(tr("V/M"),this);
vfoMemoryButton->setHidden(true);
vfoMemoryButton->setCheckable(true);
vfoMemoryButton->setFocusPolicy(Qt::NoFocus);
connect(vfoMemoryButton, &QPushButton::clicked, this, [=](bool en) {
if (en)
queue->add(priorityImmediate,queueItem(funcSelectVFO,QVariant::fromValue<vfo_t>(vfoA),false,0));
else
queue->add(priorityImmediate,queueItem(funcSplitStatus,QVariant::fromValue<uchar>(vfoMem),false,0));
});
satelliteButton=new QPushButton(tr("SAT"),this);
satelliteButton->setHidden(true);
satelliteButton->setCheckable(true);
satelliteButton->setFocusPolicy(Qt::NoFocus);
connect(satelliteButton, &QPushButton::clicked, this, [=](bool en) {
queue->add(priorityImmediate,queueItem(funcSatelliteMode,QVariant::fromValue<bool>(en),false,0));
});
2024-12-31 18:38:43 +00:00
splitButton=new QPushButton(tr("SPLIT"),this);
splitButton->setHidden(true);
splitButton->setFocusPolicy(Qt::NoFocus);
splitButton->setCheckable(true);
connect(splitButton, &QPushButton::clicked, this, [=](bool en) {
queue->add(priorityImmediate,queueItem(funcSplitStatus,QVariant::fromValue<uchar>(en),false,0));
2024-12-31 18:38:43 +00:00
});
for (uchar i=0;i<numVFO;i++)
{
2024-07-23 08:18:27 +00:00
freqCtrl* fr = new freqCtrl(this);
2024-11-12 19:32:08 +00:00
qDebug() << "Adding VFO" << i << "on receiver" << receiver;
if (i==0)
{
2024-07-23 08:18:27 +00:00
fr->setMinimumSize(280,30);
fr->setMaximumSize(280,30);
displayLayout->addWidget(fr);
2024-12-31 18:38:43 +00:00
// Add the VFO buttons here.
if (numVFO > 1) {
vfoSelectButton->setHidden(false);
displayLayout->addWidget(vfoSelectButton);
displayLSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed);
displayLayout->addSpacerItem(displayLSpacer);
if (!receiver) {
if (rigCaps->commands.contains(funcVFOEqualAB))
{
vfoSwapButton->setHidden(false);
displayLayout->addWidget(vfoSwapButton);
}
if (rigCaps->commands.contains(funcVFOEqualAB))
{
vfoEqualsButton->setHidden(false);
displayLayout->addWidget(vfoEqualsButton);
}
if(rigCaps->commands.contains(funcMemoryMode)) {
vfoMemoryButton->setHidden(false);
displayLayout->addWidget(vfoMemoryButton);
}
if(rigCaps->commands.contains(funcSatelliteMode)) {
satelliteButton->setHidden(false);
displayLayout->addWidget(satelliteButton);
}
displayMSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed);
displayLayout->addSpacerItem(displayMSpacer);
2024-12-31 18:38:43 +00:00
if (rigCaps->commands.contains(funcSplitStatus)) {
splitButton->setHidden(false);
displayLayout->addWidget(splitButton);
}
}
}
displayRSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed);
displayLayout->addSpacerItem(displayRSpacer);
} else {
2024-07-23 08:18:27 +00:00
fr->setMinimumSize(180,20);
fr->setMaximumSize(180,20);
if (!rigCaps->hasCommand29 && receiver == 1)
2025-01-06 20:16:14 +00:00
{
fr->setVisible(false);
2025-01-06 20:16:14 +00:00
}
2024-07-23 08:18:27 +00:00
displayLayout->addWidget(fr);
}
connect(fr, &freqCtrl::newFrequency, this, [=](const qint64 &freq) {
this->newFrequency(freq,i);
});
2024-03-30 21:26:39 +00:00
2024-07-23 08:18:27 +00:00
freqDisplay.append(fr);
}
2023-09-26 17:46:04 +00:00
controlLayout = new QHBoxLayout();
detachButton = new QPushButton(tr("Detach"));
detachButton->setCheckable(true);
detachButton->setToolTip(tr("Detach/re-attach scope from main window"));
detachButton->setChecked(false);
2023-06-05 08:27:37 +00:00
//scopeModeLabel = new QLabel("Spectrum Mode:");
scopeModeCombo = new QComboBox();
scopeModeCombo->setAccessibleDescription(tr("Spectrum Mode"));
2023-06-05 08:27:37 +00:00
//spanLabel = new QLabel("Span:");
spanCombo = new QComboBox();
spanCombo->setAccessibleDescription(tr("Spectrum Span"));
2023-06-05 08:27:37 +00:00
//edgeLabel = new QLabel("Edge:");
edgeCombo = new QComboBox();
edgeCombo->setAccessibleDescription(tr("Spectrum Edge"));
edgeButton = new QPushButton(tr("Custom Edge"));
edgeButton->setToolTip(tr("Define a custom (fixed) scope edge"));
toFixedButton = new QPushButton(tr("To Fixed"));
toFixedButton->setToolTip(tr("&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Press button to convert center mode spectrum to fixed mode, preserving the range. This allows you to tune without the spectrum moving, in the same currently-visible range that you see now. &lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;The currently-selected edge slot will be overridden.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;"));
holdButton = new QPushButton("HOLD");
holdButton->setCheckable(true);
holdButton->setFocusPolicy(Qt::NoFocus);
2023-06-05 08:27:37 +00:00
controlSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed);
midSpacer = new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed);
2023-09-25 13:55:27 +00:00
2023-06-05 08:27:37 +00:00
clearPeaksButton = new QPushButton("Clear Peaks");
2023-07-16 09:08:28 +00:00
2023-09-25 18:21:31 +00:00
confButton = new QPushButton("<");
confButton->setAccessibleName(tr("Configure Scope"));
confButton->setAccessibleDescription(tr("Change various settings of the current Scope"));
confButton->setToolTip(tr("Configure Scope"));
2023-09-25 18:21:31 +00:00
confButton->setFocusPolicy(Qt::NoFocus);
2023-06-05 08:27:37 +00:00
modeCombo = new QComboBox();
2025-03-02 09:17:52 +00:00
modeCombo->setToolTip(tr("Select current radio mode"));
modeCombo->setAccessibleDescription(tr("Change the current radio mode for this receiver"));
2023-06-05 08:27:37 +00:00
dataCombo = new QComboBox();
2025-03-02 09:17:52 +00:00
dataCombo->setToolTip(tr("Select data mode (if supported)"));
dataCombo->setAccessibleDescription(tr("Change the current data mode (if supported)"));
2023-06-05 08:27:37 +00:00
filterCombo = new QComboBox();
2025-03-02 09:17:52 +00:00
filterCombo->setToolTip(tr("Select current filter"));
dataCombo->setAccessibleDescription(tr("Change the current filter"));
filterShapeCombo = new QComboBox();
filterShapeCombo->setToolTip(tr("Select current filter shape"));
filterShapeCombo->setAccessibleDescription(tr("Change the current filter shape"));
if (!rigCaps->commands.contains(funcFilterShape))
{
filterShapeCombo->hide();
}
else
{
filterShapeCombo->addItem("Sharp",0);
if (rigCaps->manufacturer == manufKenwood)
{
filterShapeCombo->addItem("Medium",1);
filterShapeCombo->addItem("Soft",2);
}
else
{
filterShapeCombo->addItem("Soft",1);
}
}
roofingCombo = new QComboBox();
roofingCombo->setToolTip(tr("Select roofing filter"));
roofingCombo->setAccessibleDescription(tr("Change the current selected roofing filter"));
if (!rigCaps->commands.contains(funcRoofingFilter))
roofingCombo->hide();
2023-06-05 08:27:37 +00:00
spanCombo->setVisible(false);
edgeCombo->setVisible(false);
edgeButton->setVisible(false);
toFixedButton->setVisible(false);
2023-06-01 16:57:44 +00:00
spectrum = new QCustomPlot();
2023-09-27 10:06:55 +00:00
spectrum->xAxis->axisRect()->setAutoMargins(QCP::MarginSide::msBottom);
spectrum->yAxis->axisRect()->setAutoMargins(QCP::MarginSide::msBottom);
spectrum->xAxis->setPadding(0);
spectrum->yAxis->setPadding(0);
2023-06-01 16:57:44 +00:00
waterfall = new QCustomPlot();
2023-09-27 10:06:55 +00:00
waterfall->xAxis->axisRect()->setAutoMargins(QCP::MarginSide::msNone);
waterfall->yAxis->axisRect()->setAutoMargins(QCP::MarginSide::msNone);
waterfall->xAxis->setPadding(0);
waterfall->yAxis->setPadding(0);
2023-06-01 16:57:44 +00:00
splitter->addWidget(spectrum);
splitter->addWidget(waterfall);
splitter->setHandleWidth(5);
2023-09-27 10:06:55 +00:00
spectrum->axisRect()->setMargins(QMargins(30,0,0,0));
waterfall->axisRect()->setMargins(QMargins(30,0,0,0));
2023-06-01 16:57:44 +00:00
2023-09-26 17:46:04 +00:00
layout->addLayout(displayLayout);
2023-06-05 08:27:37 +00:00
layout->addLayout(controlLayout);
controlLayout->addWidget(detachButton);
2023-06-05 08:27:37 +00:00
controlLayout->addWidget(scopeModeCombo);
controlLayout->addWidget(spanCombo);
controlLayout->addWidget(edgeCombo);
controlLayout->addWidget(edgeButton);
controlLayout->addWidget(toFixedButton);
controlLayout->addWidget(holdButton);
2023-06-05 08:27:37 +00:00
controlLayout->addSpacerItem(controlSpacer);
controlLayout->addWidget(modeCombo);
controlLayout->addWidget(dataCombo);
controlLayout->addWidget(filterCombo);
2025-03-02 09:17:52 +00:00
controlLayout->addWidget(filterShapeCombo);
controlLayout->addWidget(roofingCombo);
2023-06-05 08:27:37 +00:00
controlLayout->addSpacerItem(midSpacer);
controlLayout->addWidget(clearPeaksButton);
2023-09-25 18:21:31 +00:00
controlLayout->addWidget(confButton);
2023-06-05 08:27:37 +00:00
this->layout->setContentsMargins(5,5,5,5);
scopeModeCombo->addItem(tr("Center Mode"), (spectrumMode_t)spectModeCenter);
scopeModeCombo->addItem(tr("Fixed Mode"), (spectrumMode_t)spectModeFixed);
scopeModeCombo->addItem(tr("Scroll-C"), (spectrumMode_t)spectModeScrollC);
scopeModeCombo->addItem(tr("Scroll-F"), (spectrumMode_t)spectModeScrollF);
2023-06-05 08:27:37 +00:00
scopeModeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
2025-02-19 14:52:53 +00:00
//edgeCombo->insertItems(0, QStringList({tr("Fixed Edge 1"),tr("Fixed Edge 2"),tr("Fixed Edge 3"),tr("Fixed Edge 4")}));
2023-06-05 08:27:37 +00:00
//edgeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
2025-02-24 12:48:23 +00:00
auto it = rigCaps->commands.find(funcScopeEdge);
if (it != rigCaps->commands.end())
2025-02-19 14:52:53 +00:00
{
2025-02-24 12:50:51 +00:00
for (int i=it->minVal; i<=it->maxVal; i++)
2025-02-24 12:48:23 +00:00
{
edgeCombo->addItem(QString("Fixed Edge %0").arg(i),QVariant::fromValue<uchar>(i));
}
2025-02-19 14:52:53 +00:00
}
2023-06-01 16:57:44 +00:00
// Spectrum Plot setup
passbandIndicator = new QCPItemRect(spectrum);
passbandIndicator->setAntialiased(true);
passbandIndicator->setPen(QPen(Qt::red));
passbandIndicator->setBrush(QBrush(Qt::red));
passbandIndicator->setSelectable(true);
pbtIndicator = new QCPItemRect(spectrum);
pbtIndicator->setAntialiased(true);
pbtIndicator->setPen(QPen(Qt::red));
pbtIndicator->setBrush(QBrush(Qt::red));
pbtIndicator->setSelectable(true);
pbtIndicator->setVisible(false);
freqIndicatorLine = new QCPItemLine(spectrum);
freqIndicatorLine->setAntialiased(true);
freqIndicatorLine->setPen(QPen(Qt::blue));
oorIndicator = new QCPItemText(spectrum);
oorIndicator->setVisible(false);
oorIndicator->setAntialiased(true);
oorIndicator->setPen(QPen(Qt::red));
oorIndicator->setBrush(QBrush(Qt::red));
oorIndicator->setFont(QFont(font().family(), 14));
oorIndicator->setPositionAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
oorIndicator->position->setType(QCPItemPosition::ptAxisRectRatio); // Positioned relative to the current plot rect
oorIndicator->setText(tr("SCOPE OUT OF RANGE"));
2023-06-01 16:57:44 +00:00
oorIndicator->position->setCoords(0.5f,0.5f);
ovfIndicator = new QCPItemText(spectrum);
ovfIndicator->setVisible(false);
ovfIndicator->setAntialiased(true);
ovfIndicator->setPen(QPen(Qt::red));
ovfIndicator->setColor(Qt::red);
ovfIndicator->setFont(QFont(font().family(), 10));
ovfIndicator->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop);
ovfIndicator->position->setType(QCPItemPosition::ptAxisRectRatio); // Positioned relative to the current plot rect
ovfIndicator->setText(tr(" OVF "));
2023-06-01 16:57:44 +00:00
ovfIndicator->position->setCoords(0.01f,0.0f);
2024-01-22 12:19:31 +00:00
redrawSpeed = new QCPItemText(spectrum);
redrawSpeed->setVisible(true);
redrawSpeed->setColor(Qt::gray);
redrawSpeed->setFont(QFont(font().family(), 8));
redrawSpeed->setPositionAlignment(Qt::AlignRight | Qt::AlignTop);
redrawSpeed->position->setType(QCPItemPosition::ptAxisRectRatio);
2025-01-14 13:35:14 +00:00
redrawSpeed->setText("");
2024-01-22 12:19:31 +00:00
redrawSpeed->position->setCoords(1.0f,0.0f);
2023-06-01 16:57:44 +00:00
spectrum->addGraph(); // primary
spectrum->addGraph(0, 0); // secondary, peaks, same axis as first.
spectrum->addLayer( "Top Layer", spectrum->layer("main"));
spectrum->graph(0)->setLayer("Top Layer");
spectrumPlasma.resize(spectrumPlasmaSizeMax);
2024-02-06 22:27:29 +00:00
for(unsigned int p=0; p < spectrumPlasmaSizeMax; p++) {
spectrumPlasma[p] = 0;
}
2023-06-01 16:57:44 +00:00
QColor color(20+200/4.0*1,70*(1.6-1/4.0), 150, 150);
spectrum->graph(1)->setLineStyle(QCPGraph::lsLine);
spectrum->graph(1)->setPen(QPen(color.lighter(200)));
spectrum->graph(1)->setBrush(QBrush(color));
freqIndicatorLine->start->setCoords(0.5, 0);
freqIndicatorLine->end->setCoords(0.5, 160);
passbandIndicator->topLeft->setCoords(0.5, 0);
passbandIndicator->bottomRight->setCoords(0.5, 160);
pbtIndicator->topLeft->setCoords(0.5, 0);
pbtIndicator->bottomRight->setCoords(0.5, 160);
// Waterfall setup
waterfall->addGraph();
colorMap = new QCPColorMap(waterfall->xAxis, waterfall->yAxis);
colorMapData = NULL;
2023-06-05 08:27:37 +00:00
2023-06-01 16:57:44 +00:00
#if QCUSTOMPLOT_VERSION < 0x020001
this->addPlottable(colorMap);
#endif
2023-09-24 23:11:37 +00:00
// Config Screen
2023-09-25 13:55:27 +00:00
rhsLayout = new QVBoxLayout();
rhsTopSpacer = new QSpacerItem(0,0,QSizePolicy::Fixed,QSizePolicy::Expanding);
rhsLayout->addSpacerItem(rhsTopSpacer);
configGroup = new QGroupBox();
rhsLayout->addWidget(configGroup);
configLayout = new QFormLayout();
2025-01-17 00:43:57 +00:00
configLayout->setHorizontalSpacing(0);
2023-09-25 13:55:27 +00:00
configGroup->setLayout(configLayout);
mainLayout->addLayout(rhsLayout);
rhsBottomSpacer = new QSpacerItem(0,0,QSizePolicy::Fixed,QSizePolicy::Expanding);
rhsLayout->addSpacerItem(rhsBottomSpacer);
2023-09-24 23:11:37 +00:00
QFont font = configGroup->font();
2023-09-25 13:55:27 +00:00
configGroup->setStyleSheet(QString("QGroupBox{border:1px solid gray;} *{padding: 0px 0px 0px 0px; margin: 0px 0px 0px 0px; font-size: %0px;}").arg(font.pointSize()-1));
2023-09-24 23:11:37 +00:00
configGroup->setMaximumWidth(240);
configRef = new QSlider(Qt::Orientation::Horizontal);
configRef->setTickInterval(50);
configRef->setSingleStep(20);
configRef->setValue(0);
configRef->setAccessibleName(tr("Scope display reference"));
configRef->setAccessibleDescription(tr("Selects the display reference for the Scope display"));
configRef->setToolTip(tr("Select display reference of scope"));
configLayout->addRow(tr("Ref"),configRef);
2023-09-24 23:11:37 +00:00
configLength = new QSlider(Qt::Orientation::Horizontal);
configLength->setRange(100,1024);
configLayout->addRow(tr("Length"),configLength);
2023-09-24 23:11:37 +00:00
configTop = new QSlider(Qt::Orientation::Horizontal);
2025-01-17 00:43:57 +00:00
configTop->setRange(0,rigCaps->spectAmpMax+10);
2023-09-26 09:32:56 +00:00
configTop->setValue(plotCeiling);
configTop->setAccessibleName(tr("Scope display ceiling"));
configTop->setAccessibleDescription(tr("Selects the display ceiling for the Scope display"));
configTop->setToolTip(tr("Select display ceiling of scope"));
configLayout->addRow(tr("Ceiling"),configTop);
2023-09-24 23:11:37 +00:00
configBottom = new QSlider(Qt::Orientation::Horizontal);
2025-01-17 00:43:57 +00:00
configBottom->setRange(0,rigCaps->spectAmpMax+10);
2023-09-26 09:32:56 +00:00
configBottom->setValue(plotFloor);
configBottom->setAccessibleName(tr("Scope display floor"));
configBottom->setAccessibleDescription(tr("Selects the display floor for the Scope display"));
configBottom->setToolTip(tr("Select display floor of scope"));
configLayout->addRow(tr("Floor"),configBottom);
2023-09-24 23:11:37 +00:00
configSpeed = new QComboBox();
configSpeed->addItem(tr("Speed Fast"),QVariant::fromValue(uchar(0)));
configSpeed->addItem(tr("Speed Mid"),QVariant::fromValue(uchar(1)));
configSpeed->addItem(tr("Speed Slow"),QVariant::fromValue(uchar(2)));
2023-09-24 23:11:37 +00:00
configSpeed->setCurrentIndex(configSpeed->findData(currentSpeed));
configSpeed->setAccessibleName(tr("Waterfall display speed"));
configSpeed->setAccessibleDescription(tr("Selects the speed for the waterfall display"));
configSpeed->setToolTip(tr("Waterfall Speed"));
configLayout->addRow(tr("Speed"),configSpeed);
2023-09-24 23:11:37 +00:00
configTheme = new QComboBox();
configTheme->setAccessibleName(tr("Waterfall display color theme"));
configTheme->setAccessibleDescription(tr("Selects the color theme for the waterfall display"));
configTheme->setToolTip(tr("Waterfall color theme"));
configTheme->addItem("Jet", QCPColorGradient::gpJet);
configTheme->addItem("Cold", QCPColorGradient::gpCold);
configTheme->addItem("Hot", QCPColorGradient::gpHot);
configTheme->addItem("Therm", QCPColorGradient::gpThermal);
configTheme->addItem("Night", QCPColorGradient::gpNight);
configTheme->addItem("Ion", QCPColorGradient::gpIon);
configTheme->addItem("Gray", QCPColorGradient::gpGrayscale);
configTheme->addItem("Geo", QCPColorGradient::gpGeography);
configTheme->addItem("Hues", QCPColorGradient::gpHues);
configTheme->addItem("Polar", QCPColorGradient::gpPolar);
configTheme->addItem("Spect", QCPColorGradient::gpSpectrum);
configTheme->addItem("Candy", QCPColorGradient::gpCandy);
2023-09-24 23:11:37 +00:00
configTheme->setSizeAdjustPolicy(QComboBox::AdjustToContents);
configLayout->addRow(tr("Theme"),configTheme);
2023-09-24 23:11:37 +00:00
configPbtInner = new QSlider(Qt::Orientation::Horizontal);
2025-01-30 11:47:05 +00:00
2023-09-24 23:11:37 +00:00
configPbtInner->setRange(0,255);
configLayout->addRow(tr("PBT Inner"),configPbtInner);
2023-09-24 23:11:37 +00:00
configPbtOuter = new QSlider(Qt::Orientation::Horizontal);
configPbtOuter->setRange(0,255);
configLayout->addRow(tr("PBT Outer"),configPbtOuter);
2023-09-24 23:11:37 +00:00
2024-10-24 12:08:15 +00:00
configIfLayout = new QHBoxLayout();
2023-09-24 23:11:37 +00:00
configIfShift = new QSlider(Qt::Orientation::Horizontal);
configIfShift->setRange(0,255);
2024-10-24 12:08:15 +00:00
if (rigCaps != Q_NULLPTR && !rigCaps->commands.contains(funcIFShift)){
configIfShift->setEnabled(true);
configIfShift->setValue(128);
} else {
configIfShift->setEnabled(false);
}
configResetIf = new QPushButton("R");
configIfLayout->addWidget(configIfShift);
configIfLayout->addWidget(configResetIf);
configLayout->addRow(tr("IF Shift"),configIfLayout);
2023-09-24 23:11:37 +00:00
configFilterWidth = new QSlider(Qt::Orientation::Horizontal);
configFilterWidth->setRange(0,10000);
configLayout->addRow(tr("Fill Width"),configFilterWidth);
2023-09-24 23:11:37 +00:00
2025-01-17 00:43:57 +00:00
configScopeEnabled = new QCheckBox(tr("Scope Enabled"));
configScopeEnabled->setChecked(true);
2025-01-17 00:43:57 +00:00
configLayout->addRow(configScopeEnabled);
frequencyNotificationLockoutTimer = new QTimer();
connect(frequencyNotificationLockoutTimer, SIGNAL(timeout()), this, SLOT(freqNoteLockTimerSlot()));
frequencyNotificationLockoutTimer->setInterval(200);
frequencyNotificationLockoutTimer->setSingleShot(true);
2023-09-24 23:11:37 +00:00
connect(configLength, &QSlider::valueChanged, this, [=](const int &val) {
//prepareWf(val);
changeWfLength(val);
emit updateSettings(receiver,currentTheme,wfLength,plotFloor,plotCeiling);
2023-09-24 23:11:37 +00:00
});
connect(configBottom, &QSlider::valueChanged, this, [=](const int &val) {
this->plotFloor = val;
2023-09-26 09:32:56 +00:00
this->wfFloor = val;
2023-09-24 23:11:37 +00:00
this->setRange(plotFloor,plotCeiling);
emit updateSettings(receiver,currentTheme,wfLength,plotFloor,plotCeiling);
2023-09-24 23:11:37 +00:00
});
connect(configTop, &QSlider::valueChanged, this, [=](const int &val) {
this->plotCeiling = val;
2023-09-26 09:32:56 +00:00
this->wfCeiling = val;
2023-09-24 23:11:37 +00:00
this->setRange(plotFloor,plotCeiling);
emit updateSettings(receiver,currentTheme,wfLength,plotFloor,plotCeiling);
2023-09-24 23:11:37 +00:00
});
2025-01-30 11:47:05 +00:00
if (rigCaps->commands.contains(funcScopeRef))
{
auto v = rigCaps->commands.find(funcScopeRef);
configRef->setRange(v.value().minVal,v.value().maxVal);
connect(configRef, &QSlider::valueChanged, this, [=](const int &val) {
currentRef = (val/5) * 5; // rounded to "nearest 5"
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcScopeRef,QVariant::fromValue(currentRef),false,t.receiver));
2025-01-30 11:47:05 +00:00
});
}
2023-09-24 23:11:37 +00:00
connect(configSpeed, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](const int &val) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcScopeSpeed,QVariant::fromValue(configSpeed->itemData(val)),false,t.receiver));
2023-09-24 23:11:37 +00:00
});
connect(configTheme, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](const int &val) {
Q_UNUSED(val)
currentTheme = configTheme->currentData().value<QCPColorGradient::GradientPreset>();
colorMap->setGradient(currentTheme);
emit updateSettings(receiver,currentTheme,wfLength,plotFloor,plotCeiling);
2023-09-24 23:11:37 +00:00
});
2025-01-30 11:47:05 +00:00
if (rigCaps->commands.contains(funcPBTInner))
{
auto v = rigCaps->commands.find(funcPBTInner);
configPbtInner->setRange(v.value().minVal,v.value().maxVal);
connect(configPbtInner, &QSlider::valueChanged, this, [=](const int &val) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue<ushort>(val),false,t.receiver));
});
}
if (rigCaps->commands.contains(funcPBTOuter))
{
auto v = rigCaps->commands.find(funcPBTOuter);
configPbtOuter->setRange(v.value().minVal,v.value().maxVal);
connect(configPbtOuter, &QSlider::valueChanged, this, [=](const int &val) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue<ushort>(val),false,t.receiver));
});
}
2023-09-24 23:11:37 +00:00
connect(configIfShift, &QSlider::valueChanged, this, [=](const int &val) {
2024-10-24 12:08:15 +00:00
if (rigCaps != Q_NULLPTR && rigCaps->commands.contains(funcIFShift)) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcIFShift,QVariant::fromValue<ushort>(val),false,t.receiver));
2024-10-24 12:08:15 +00:00
} else {
static int previousIFShift=128; // Default value
unsigned char inner = configPbtInner->value();
unsigned char outer = configPbtOuter->value();
int shift = val - previousIFShift;
inner = qMax( 0, qMin(255,int (inner + shift)) );
outer = qMax( 0, qMin(255,int (outer + shift)) );
configPbtInner->setValue(inner);
configPbtOuter->setValue(outer);
previousIFShift = val;
}
});
connect(configResetIf, &QPushButton::clicked, this, [=](const bool &val) {
Q_UNUSED(val)
2024-10-24 12:08:15 +00:00
double pbFreq = (pbtDefault / passbandWidth) * 127.0;
qint16 newFreq = pbFreq + 128;
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue<ushort>(newFreq),false,t.receiver));
queue->addUnique(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue<ushort>(newFreq),false,t.receiver));
2024-10-24 12:08:15 +00:00
configIfShift->blockSignals(true);
configIfShift->setValue(128);
configIfShift->blockSignals(false);
2023-09-24 23:11:37 +00:00
});
2024-10-24 12:08:15 +00:00
2025-01-30 11:47:05 +00:00
if (rigCaps->commands.contains(funcFilterWidth))
{
connect(configFilterWidth, &QSlider::valueChanged, this, [=](const int &val) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcFilterWidth,QVariant::fromValue<ushort>(val),false,t.receiver));
});
}
2023-09-24 23:11:37 +00:00
2025-01-17 00:43:57 +00:00
#if (QT_VERSION < QT_VERSION_CHECK(6,7,0))
connect(configScopeEnabled, &QCheckBox::stateChanged, this, [=](const int &val) {
#else
connect(configScopeEnabled, &QCheckBox::checkStateChanged, this, [=](const Qt::CheckState &val) {
#endif
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityHighest,queueItem(funcScopeOnOff,QVariant::fromValue<bool>(val),false,t.receiver));
qInfo() << "Queueing command to set scope to:" << bool(val);
});
2023-09-24 23:11:37 +00:00
2025-01-17 00:43:57 +00:00
configGroup->setVisible(false);
2023-09-24 23:11:37 +00:00
// Connections
connect(detachButton,SIGNAL(toggled(bool)), this, SLOT(detachScope(bool)));
connect(scopeModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int val){
spectrumMode_t s = scopeModeCombo->itemData(val).value<spectrumMode_t>();
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcScopeMode,QVariant::fromValue(s),false,t.receiver));
showHideControls(s);
2025-01-14 13:35:14 +00:00
currentScopeMode = s;
});
connect(spanCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int val){
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
2025-02-19 15:13:08 +00:00
queue->addUnique(priorityImmediate,queueItem(funcScopeSpan,spanCombo->itemData(val),false,t.receiver));
});
2023-09-25 18:35:22 +00:00
connect(confButton,SIGNAL(clicked()), this, SLOT(configPressed()),Qt::QueuedConnection);
2023-06-05 08:27:37 +00:00
2023-09-25 18:35:22 +00:00
connect(toFixedButton,SIGNAL(clicked()), this, SLOT(toFixedPressed()));
connect(edgeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int val){
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
2025-02-19 15:13:08 +00:00
queue->addUnique(priorityImmediate,queueItem(funcScopeEdge,edgeCombo->itemData(val),false,t.receiver));
});
2023-09-25 18:35:22 +00:00
connect(edgeButton,SIGNAL(clicked()), this, SLOT(customSpanPressed()));
2023-06-05 08:27:37 +00:00
connect(holdButton, &QPushButton::toggled, this, [=](const bool &val) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->add(priorityImmediate,queueItem(funcScopeHold,QVariant::fromValue<bool>(val),false,t.receiver));
});
2023-06-05 08:27:37 +00:00
connect(modeCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedMode(int)));
connect(filterCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedMode(int)));
2025-03-02 09:17:52 +00:00
connect(filterShapeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int val){
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
2025-03-02 10:21:49 +00:00
uchar f = uchar(filterShapeCombo->itemData(val).toInt() + (filterCombo->currentData().toInt() * 10));
queue->addUnique(priorityImmediate,queueItem(funcFilterShape,QVariant::fromValue<uchar>(f),false,t.receiver));
2025-03-02 09:17:52 +00:00
});
connect(roofingCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int val){
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
2025-03-02 10:21:49 +00:00
uchar f = uchar(roofingCombo->itemData(val).toInt() + (filterCombo->currentData().toInt() * 10));
queue->addUnique(priorityImmediate,queueItem(funcRoofingFilter,QVariant::fromValue<uchar>(f),false,t.receiver));
2025-03-02 09:17:52 +00:00
});
2023-06-05 08:27:37 +00:00
connect(dataCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(updatedMode(int)));
2023-09-25 18:35:22 +00:00
connect(clearPeaksButton,SIGNAL(clicked()), this, SLOT(clearPeaks()));
2023-06-05 08:27:37 +00:00
2023-06-05 20:08:01 +00:00
connect(spectrum, SIGNAL(mouseDoubleClick(QMouseEvent*)), this, SLOT(doubleClick(QMouseEvent*)));
connect(waterfall, SIGNAL(mouseDoubleClick(QMouseEvent*)), this, SLOT(doubleClick(QMouseEvent*)));
2023-06-05 08:27:37 +00:00
connect(spectrum, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(scopeClick(QMouseEvent*)));
connect(waterfall, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(waterfallClick(QMouseEvent*)));
connect(spectrum, SIGNAL(mouseRelease(QMouseEvent*)), this, SLOT(scopeMouseRelease(QMouseEvent*)));
connect(spectrum, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(scopeMouseMove(QMouseEvent *)));
connect(waterfall, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(scroll(QWheelEvent*)));
connect(spectrum, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(scroll(QWheelEvent*)));
showHideControls(spectrumMode_t::spectModeCenter);
2024-11-14 00:21:18 +00:00
lastData.start();
2023-06-01 16:57:44 +00:00
}
2024-06-03 23:25:11 +00:00
2025-01-06 23:10:11 +00:00
receiverWidget::~receiverWidget(){
2024-06-12 16:11:01 +00:00
QMutableVectorIterator<bandIndicator> it(bandIndicators);
while (it.hasNext())
{
auto band = it.next();
spectrum->removeItem(band.line);
spectrum->removeItem(band.text);
it.remove();
}
QMutableMapIterator<QString, spotData *> sp(clusterSpots);
while (sp.hasNext())
{
auto spot = sp.next();
spectrum->removeItem(spot.value()->text);
delete spot.value();
sp.remove();
}
2024-06-03 23:25:11 +00:00
if(colorMapData != Q_NULLPTR)
{
delete colorMapData;
}
}
2024-07-23 08:18:27 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::setSeparators(QChar gsep, QChar dsep)
2024-07-23 08:18:27 +00:00
{
2024-12-31 18:38:43 +00:00
for (const auto &disp : freqDisplay)
2024-07-23 08:18:27 +00:00
{
2024-11-12 19:32:08 +00:00
qDebug(logRig()) << "Configuring separators:" << gsep << "and" << dsep;
2024-07-23 08:18:27 +00:00
disp->setSeparators(gsep,dsep);
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::prepareScope(uint maxAmp, uint spectWidth)
{
this->spectWidth = spectWidth;
this->maxAmp = maxAmp;
}
2023-06-05 08:27:37 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::changeWfLength(uint wf)
{
if(!scopePrepared)
return;
QMutexLocker locker(&mutex);
this->wfLength = wf;
colorMap->data()->clear();
colorMap->data()->setValueRange(QCPRange(0, wfLength-1));
colorMap->data()->setKeyRange(QCPRange(0, spectWidth-1));
colorMap->setDataRange(QCPRange(plotFloor, plotCeiling));
colorMap->setGradient(static_cast<QCPColorGradient::GradientPreset>(currentTheme));
if(colorMapData != Q_NULLPTR)
{
delete colorMapData;
}
colorMapData = new QCPColorMapData(spectWidth, wfLength, QCPRange(0, spectWidth-1), QCPRange(0, wfLength-1));
colorMap->setData(colorMapData,true); // Copy the colorMap so deleting it won't result in crash!
waterfall->yAxis->setRange(0,wfLength - 1);
//waterfall->replot();
}
2024-06-10 22:58:33 +00:00
2025-01-06 23:10:11 +00:00
bool receiverWidget::prepareWf(uint wf)
2023-06-01 16:57:44 +00:00
{
QMutexLocker locker(&mutex);
bool ret=true;
this->wfLength = wf;
2023-09-26 09:32:56 +00:00
configLength->blockSignals(true);
configLength->setValue(this->wfLength);
configLength->blockSignals(false);
2023-06-01 16:57:44 +00:00
this->wfLengthMax = 1024;
// Initialize before use!
QByteArray empty((int)spectWidth, '\x01');
spectrumPeaks = QByteArray( (int)spectWidth, '\x01' );
//unsigned int oldSize = wfimage.size();
if (!wfimage.empty() && wfimage.first().size() != spectWidth)
2023-06-01 16:57:44 +00:00
{
// Width of waterfall has changed!
wfimage.clear();
2023-06-01 16:57:44 +00:00
}
for(unsigned int i = wfimage.size(); i < wfLengthMax; i++)
{
wfimage.append(empty);
}
//wfimage.remove(wfLength, wfimage.size()-wfLength);
2023-06-01 16:57:44 +00:00
wfimage.squeeze();
2023-06-01 16:57:44 +00:00
colorMap->data()->clear();
colorMap->data()->setValueRange(QCPRange(0, wfLength-1));
colorMap->data()->setKeyRange(QCPRange(0, spectWidth-1));
colorMap->setDataRange(QCPRange(plotFloor, plotCeiling));
colorMap->setGradient(static_cast<QCPColorGradient::GradientPreset>(currentTheme));
if(colorMapData != Q_NULLPTR)
{
delete colorMapData;
}
colorMapData = new QCPColorMapData(spectWidth, wfLength, QCPRange(0, spectWidth-1), QCPRange(0, wfLength-1));
colorMap->setData(colorMapData,true); // Copy the colorMap so deleting it won't result in crash!
2023-06-01 16:57:44 +00:00
waterfall->yAxis->setRangeReversed(true);
waterfall->xAxis->setVisible(false);
clearPeaks();
clearPlasma();
2023-06-01 16:57:44 +00:00
scopePrepared = true;
return ret;
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setRange(int floor, int ceiling)
2023-06-01 16:57:44 +00:00
{
2023-09-26 09:32:56 +00:00
plotFloor = floor;
plotCeiling = ceiling;
wfFloor = floor;
wfCeiling = ceiling;
2023-06-01 16:57:44 +00:00
maxAmp = ceiling;
if (spectrum != Q_NULLPTR)
spectrum->yAxis->setRange(QCPRange(floor, ceiling));
if (colorMap != Q_NULLPTR)
colorMap->setDataRange(QCPRange(floor,ceiling));
2023-09-26 09:32:56 +00:00
configBottom->blockSignals(true);
configBottom->setValue(floor);
configBottom->blockSignals(false);
configTop->blockSignals(true);
configTop->setValue(ceiling);
configTop->blockSignals(false);
2024-06-10 22:58:33 +00:00
// Redraw band lines and eventually memory markers!
2024-06-12 16:11:01 +00:00
for (auto &b: bandIndicators)
2024-06-10 22:58:33 +00:00
{
2024-06-12 16:11:01 +00:00
b.line->start->setCoords(b.line->start->coords().x(), spectrum->yAxis->range().upper-5);
b.line->end->setCoords(b.line->end->coords().x(), spectrum->yAxis->range().upper-5);
b.text->position->setCoords(b.text->position->coords().x(), spectrum->yAxis->range().upper-10);
2024-06-10 22:58:33 +00:00
}
2023-06-01 16:57:44 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::colorPreset(colorPrefsType *cp)
2023-06-01 16:57:44 +00:00
{
if (cp == Q_NULLPTR)
{
return;
}
colors = *cp;
spectrum->setBackground(cp->plotBackground);
spectrum->xAxis->grid()->setPen(cp->gridColor);
spectrum->yAxis->grid()->setPen(cp->gridColor);
spectrum->legend->setTextColor(cp->textColor);
spectrum->legend->setBorderPen(cp->gridColor);
spectrum->legend->setBrush(cp->gridColor);
spectrum->xAxis->setTickLabelColor(cp->textColor);
spectrum->xAxis->setLabelColor(cp->gridColor);
spectrum->yAxis->setTickLabelColor(cp->textColor);
spectrum->yAxis->setLabelColor(cp->gridColor);
spectrum->xAxis->setBasePen(cp->axisColor);
spectrum->xAxis->setTickPen(cp->axisColor);
spectrum->yAxis->setBasePen(cp->axisColor);
spectrum->yAxis->setTickPen(cp->axisColor);
freqIndicatorLine->setPen(QPen(cp->tuningLine));
passbandIndicator->setPen(QPen(cp->passband));
passbandIndicator->setBrush(QBrush(cp->passband));
pbtIndicator->setPen(QPen(cp->pbt));
pbtIndicator->setBrush(QBrush(cp->pbt));
spectrum->graph(0)->setPen(QPen(cp->spectrumLine));
if(cp->useSpectrumFillGradient) {
spectrumGradient.setStart(QPointF(0,1));
spectrumGradient.setFinalStop(QPointF(0,0));
2025-02-17 20:19:35 +00:00
spectrumGradient.setCoordinateMode(QLinearGradient::StretchToDeviceMode);
//spectrumGradient.setColorAt(0, cp->spectrumFillBot);
spectrumGradient.setColorAt(0.1, cp->spectrumFillBot);
spectrumGradient.setColorAt(1, cp->spectrumFillTop);
spectrum->graph(0)->setBrush(QBrush(spectrumGradient));
} else {
spectrum->graph(0)->setBrush(QBrush(cp->spectrumFill));
}
2023-06-01 16:57:44 +00:00
spectrum->graph(1)->setPen(QPen(cp->underlayLine));
if(cp->useUnderlayFillGradient) {
underlayGradient.setStart(QPointF(0,1));
underlayGradient.setFinalStop(QPointF(0,0));
2025-02-17 20:19:35 +00:00
underlayGradient.setCoordinateMode(QLinearGradient::StretchToDeviceMode);
//underlayGradient.setColorAt(0, cp->underlayFillBot);
underlayGradient.setColorAt(0.1, cp->underlayFillBot);
underlayGradient.setColorAt(1, cp->underlayFillTop);
spectrum->graph(1)->setBrush(QBrush(underlayGradient));
} else {
spectrum->graph(1)->setBrush(QBrush(cp->underlayFill));
}
2023-06-01 16:57:44 +00:00
waterfall->yAxis->setBasePen(cp->wfAxis);
waterfall->yAxis->setTickPen(cp->wfAxis);
waterfall->xAxis->setBasePen(cp->wfAxis);
waterfall->xAxis->setTickPen(cp->wfAxis);
waterfall->xAxis->setLabelColor(cp->wfGrid);
waterfall->yAxis->setLabelColor(cp->wfGrid);
waterfall->xAxis->setTickLabelColor(cp->wfText);
waterfall->yAxis->setTickLabelColor(cp->wfText);
waterfall->setBackground(cp->wfBackground);
holdButton->setStyleSheet(QString("QPushButton {background-color: %0;} QPushButton:checked {background-color: %1;border:1px solid;}")
2025-01-01 13:40:58 +00:00
.arg(cp->buttonOff.name(QColor::HexArgb),cp->buttonOn.name(QColor::HexArgb)));
splitButton->setStyleSheet(QString("QPushButton {background-color: %0;} QPushButton:checked {background-color: %1;border:1px solid;}")
.arg(cp->buttonOff.name(QColor::HexArgb),cp->buttonOn.name(QColor::HexArgb)));
satelliteButton->setStyleSheet(QString("QPushButton {background-color: %0;} QPushButton:checked {background-color: %1;border:1px solid;}")
.arg(cp->buttonOff.name(QColor::HexArgb),cp->buttonOn.name(QColor::HexArgb)));
2025-01-01 13:40:58 +00:00
vfoSelectButton->setStyleSheet(QString("QPushButton {background-color: %0;} QPushButton:checked {background-color: %1;border:1px solid;}")
.arg(cp->buttonOff.name(QColor::HexArgb),cp->buttonOn.name(QColor::HexArgb)));
2023-06-01 16:57:44 +00:00
}
2025-01-06 23:10:11 +00:00
bool receiverWidget::updateScope(scopeData data)
2023-06-01 16:57:44 +00:00
{
if (!scopePrepared )
{
return false;
}
2024-11-14 00:33:10 +00:00
if (!lastData.isValid())
{
lastData.start();
}
if (!bandIndicatorsVisible) {
showBandIndicators(true);
}
2024-11-14 00:21:18 +00:00
//qint64 spectime = 0;
2023-06-01 16:57:44 +00:00
bool updateRange = false;
if (data.startFreq != lowerFreq || data.endFreq != upperFreq)
{
if(underlayMode == underlayPeakHold)
{
// TODO: create non-button function to do this
// This will break if the button is ever moved or renamed.
clearPeaks();
}
// Inform other threads (cluster) that the frequency range has changed.
emit frequencyRange(receiver, data.startFreq, data.endFreq);
2023-06-01 16:57:44 +00:00
}
lowerFreq = data.startFreq;
upperFreq = data.endFreq;
//qInfo(logSystem()) << "start: " << data.startFreq << " end: " << data.endFreq;
quint16 specLen = data.data.length();
2023-09-23 10:37:55 +00:00
if (specLen != spectWidth)
{
qWarning(logSystem()) << "Spectrum length error, expected" << spectWidth << "got" << specLen << "(one can be ignored for USB connection)";
2023-09-23 10:37:55 +00:00
return false;
}
2023-06-01 16:57:44 +00:00
QVector <double> x(spectWidth), y(spectWidth), y2(spectWidth);
for(int i=0; i < spectWidth; i++)
{
x[i] = (i * (data.endFreq-data.startFreq)/spectWidth) + data.startFreq;
}
for(int i=0; i< specLen; i++)
{
2024-08-13 12:19:50 +00:00
y[i] = (quint8)data.data[i];
2023-06-01 16:57:44 +00:00
if(underlayMode == underlayPeakHold)
{
2024-08-13 12:19:50 +00:00
if((quint8)data.data[i] > (quint8)spectrumPeaks[i])
2023-06-01 16:57:44 +00:00
{
2024-05-19 20:21:09 +00:00
spectrumPeaks[i] = data.data[i];
2023-06-01 16:57:44 +00:00
}
2024-08-13 12:19:50 +00:00
y2[i] = (quint8)spectrumPeaks[i];
2023-06-01 16:57:44 +00:00
}
}
plasmaMutex.lock();
spectrumPlasma[spectrumPlasmaPosition] = data.data;
spectrumPlasmaPosition = (spectrumPlasmaPosition+1) % spectrumPlasmaSizeCurrent;
//spectrumPlasma.push_front(data.data);
// if(spectrumPlasma.size() > (int)spectrumPlasmaSizeCurrent)
// {
// // If we have pushed_front more than spectrumPlasmaSize,
// // then we cut one off the back.
// spectrumPlasma.pop_back();
// }
2023-06-01 16:57:44 +00:00
plasmaMutex.unlock();
2024-12-27 20:40:35 +00:00
mutex.lock();
2023-06-01 16:57:44 +00:00
if ((plotFloor != oldPlotFloor) || (plotCeiling != oldPlotCeiling)){
updateRange = true;
}
#if QCUSTOMPLOT_VERSION < 0x020000
spectrum->graph(0)->setData(x, y);
#else
spectrum->graph(0)->setData(x, y, true);
#endif
2024-01-22 12:19:31 +00:00
2023-06-01 16:57:44 +00:00
if((freq.MHzDouble < data.endFreq) && (freq.MHzDouble > data.startFreq))
{
freqIndicatorLine->start->setCoords(freq.MHzDouble, 0);
freqIndicatorLine->end->setCoords(freq.MHzDouble, maxAmp);
double pbStart = 0.0;
double pbEnd = 0.0;
2023-06-05 08:27:37 +00:00
switch (mode.mk)
2023-06-01 16:57:44 +00:00
{
case modeLSB:
2024-06-10 22:58:33 +00:00
case modeRTTY_R:
2023-06-01 16:57:44 +00:00
case modePSK_R:
2025-01-30 11:47:05 +00:00
if (rigCaps->manufacturer == manufKenwood) {
pbStart = freq.MHzDouble-passbandWidth;
pbEnd = freq.MHzDouble;
} else {
pbStart = freq.MHzDouble - passbandCenterFrequency - (passbandWidth / 2);
pbEnd = freq.MHzDouble - passbandCenterFrequency + (passbandWidth / 2);
}
2023-06-01 16:57:44 +00:00
break;
case modeCW:
if (passbandWidth < 0.0006) {
pbStart = freq.MHzDouble - (passbandWidth / 2);
pbEnd = freq.MHzDouble + (passbandWidth / 2);
}
else {
pbStart = freq.MHzDouble + passbandCenterFrequency - passbandWidth;
pbEnd = freq.MHzDouble + passbandCenterFrequency;
}
break;
case modeCW_R:
if (passbandWidth < 0.0006) {
pbStart = freq.MHzDouble - (passbandWidth / 2);
pbEnd = freq.MHzDouble + (passbandWidth / 2);
}
else {
pbStart = freq.MHzDouble - passbandCenterFrequency;
pbEnd = freq.MHzDouble + passbandWidth - passbandCenterFrequency;
}
break;
2023-06-01 16:57:44 +00:00
default:
2025-01-30 11:47:05 +00:00
if (rigCaps->manufacturer == manufKenwood) {
pbStart = freq.MHzDouble;
pbEnd = freq.MHzDouble+passbandWidth;
} else {
pbStart = freq.MHzDouble + passbandCenterFrequency - (passbandWidth / 2);
pbEnd = freq.MHzDouble + passbandCenterFrequency + (passbandWidth / 2);
}
2023-06-01 16:57:44 +00:00
break;
}
passbandIndicator->topLeft->setCoords(pbStart, 0);
passbandIndicator->bottomRight->setCoords(pbEnd, maxAmp);
2023-06-05 08:27:37 +00:00
if ((mode.mk == modeCW || mode.mk == modeCW_R) && passbandWidth > 0.0006)
2023-06-01 16:57:44 +00:00
{
pbtDefault = round((passbandWidth - (cwPitch / 1000000.0)) * 200000.0) / 200000.0;
}
else
{
pbtDefault = 0.0;
}
2024-11-07 18:59:38 +00:00
if ((PBTInner - pbtDefault || PBTOuter - pbtDefault) && passbandAction != passbandResizing && mode.mk != modeFM && mode.mk != modeWFM)
2023-06-01 16:57:44 +00:00
{
pbtIndicator->setVisible(true);
}
else
{
pbtIndicator->setVisible(false);
}
/*
pbtIndicator displays the intersection between PBTInner and PBTOuter
*/
2023-06-05 08:27:37 +00:00
if (mode.mk == modeLSB || mode.mk == modeCW || mode.mk == modeRTTY) {
2023-06-01 16:57:44 +00:00
pbtIndicator->topLeft->setCoords(qMax(pbStart - (PBTInner / 2) + (pbtDefault / 2), pbStart - (PBTOuter / 2) + (pbtDefault / 2)), 0);
pbtIndicator->bottomRight->setCoords(qMin(pbStart - (PBTInner / 2) + (pbtDefault / 2) + passbandWidth,
pbStart - (PBTOuter / 2) + (pbtDefault / 2) + passbandWidth), maxAmp);
}
else
{
pbtIndicator->topLeft->setCoords(qMax(pbStart + (PBTInner / 2) - (pbtDefault / 2), pbStart + (PBTOuter / 2) - (pbtDefault / 2)), 0);
pbtIndicator->bottomRight->setCoords(qMin(pbStart + (PBTInner / 2) - (pbtDefault / 2) + passbandWidth,
pbStart + (PBTOuter / 2) - (pbtDefault / 2) + passbandWidth), maxAmp);
}
//qDebug() << "Default" << pbtDefault << "Inner" << PBTInner << "Outer" << PBTOuter << "Pass" << passbandWidth << "Center" << passbandCenterFrequency << "CW" << cwPitch;
}
#if QCUSTOMPLOT_VERSION < 0x020000
if (underlayMode == underlayPeakHold) {
spectrum->graph(1)->setData(x, y2); // peaks
}
else if (underlayMode != underlayNone) {
computePlasma();
spectrum->graph(1)->setData(x, spectrumPlasmaLine);
}
else {
spectrum->graph(1)->setData(x, y2); // peaks, but probably cleared out
}
#else
if (underlayMode == underlayPeakHold) {
spectrum->graph(1)->setData(x, y2, true); // peaks
}
else if (underlayMode != underlayNone) {
computePlasma();
spectrum->graph(1)->setData(x, spectrumPlasmaLine, true);
}
else {
spectrum->graph(1)->setData(x, y2, true); // peaks, but probably cleared out
}
#endif
if(updateRange)
spectrum->yAxis->setRange(plotFloor, plotCeiling);
spectrum->xAxis->setRange(data.startFreq, data.endFreq);
2024-01-22 12:19:31 +00:00
2023-06-01 16:57:44 +00:00
if(specLen == spectWidth)
{
wfimage.prepend(data.data);
wfimage.pop_back();
QByteArray wfRow;
// Waterfall:
for(int row = 0; row < wfLength; row++)
{
2024-05-19 20:21:09 +00:00
wfRow = wfimage[row];
2023-06-01 16:57:44 +00:00
for(int col = 0; col < spectWidth; col++)
{
2024-08-13 12:19:50 +00:00
colorMap->data()->setCell( col, row, (quint8)wfRow[col]);
2023-06-01 16:57:44 +00:00
}
}
if(updateRange)
{
colorMap->setDataRange(QCPRange(wfFloor, wfCeiling));
}
waterfall->yAxis->setRange(0,wfLength - 1);
waterfall->xAxis->setRange(0, spectWidth-1);
2024-11-14 00:21:18 +00:00
2023-06-01 16:57:44 +00:00
}
oldPlotFloor = plotFloor;
oldPlotCeiling = plotCeiling;
if (data.oor && !oorIndicator->visible()) {
oorIndicator->setVisible(true);
qInfo(logSystem()) << "Scope out of range";
} else if (!data.oor && oorIndicator->visible()) {
oorIndicator->setVisible(false);
}
2024-01-22 12:23:51 +00:00
2024-11-14 00:56:31 +00:00
#if QCUSTOMPLOT_VERSION >= 0x020100
2024-11-14 00:56:31 +00:00
/*
* Hopefully temporary workaround for large scopes taking longer to replot than the time
* between scope data packets arriving from the radio, which were causing the UI to freeze
*
* Long term we should rewrite the scope/waterfall code to either use custom widgets, or
* convert to Qwt (or other suitable package) with better performance than QCP.
*
*/
if (lastData.elapsed() > (spectrum->replotTime(false)+waterfall->replotTime(false)))
{
spectrum->replot();
waterfall->replot();
lastData.restart();
redrawSpeed->setText(" ");
} else {
redrawSpeed->setText("*");
}
2023-06-01 16:57:44 +00:00
2024-11-18 09:03:14 +00:00
emit spectrumTime(spectrum->replotTime(false));
emit waterfallTime(waterfall->replotTime(false));
#else
spectrum->replot();
waterfall->replot();
lastData.restart();
#endif
2024-11-18 09:03:14 +00:00
mutex.unlock();
emit sendScopeImage(receiver);
2023-06-01 16:57:44 +00:00
return true;
}
// Plasma functions
2025-01-06 23:10:11 +00:00
void receiverWidget::resizePlasmaBuffer(int size) {
// QMutexLocker locker(&plasmaMutex);
qDebug() << "Resizing plasma buffer via parameter, from oldsize " << spectrumPlasmaSizeCurrent << " to new size: " << size;
spectrumPlasmaSizeCurrent = size;
return;
2023-06-01 16:57:44 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::clearPeaks()
2023-06-01 16:57:44 +00:00
{
// Clear the spectrum peaks as well as the plasma buffer
2023-06-01 16:57:44 +00:00
spectrumPeaks = QByteArray( (int)spectWidth, '\x01' );
//clearPlasma();
2023-06-01 16:57:44 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::clearPlasma()
2023-06-01 16:57:44 +00:00
{
// Clear the buffer of spectrum used for peak and average computation.
// This is only needed one time, when the VFO is created with spectrum size info.
2023-06-01 16:57:44 +00:00
QMutexLocker locker(&plasmaMutex);
QByteArray empty((int)spectWidth, '\x01');
int pSize = spectrumPlasma.size();
for(int i=0; i < pSize; i++)
{
spectrumPlasma[i] = empty;
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::computePlasma()
2023-06-01 16:57:44 +00:00
{
QMutexLocker locker(&plasmaMutex);
// Spec PlasmaLine is a single line of spectrum, ~~600 pixels or however many the radio provides.
// This changes width only when we connect to a new radio.
if(spectrumPlasmaLine.size() != spectWidth) {
spectrumPlasmaLine.clear();
spectrumPlasmaLine.resize(spectWidth);
}
// spectrumPlasma is the bufffer of spectrum lines to use when computing the average or peak.
int specPlasmaSize = spectrumPlasmaSizeCurrent; // go only this far in
2023-06-01 16:57:44 +00:00
if(underlayMode == underlayAverageBuffer)
{
for(int col=0; col < spectWidth; col++)
{
for(int pos=0; pos < specPlasmaSize; pos++)
{
2024-08-13 12:19:50 +00:00
spectrumPlasmaLine[col] += (quint8)spectrumPlasma[pos][col];
2023-06-01 16:57:44 +00:00
}
2024-05-19 20:21:09 +00:00
spectrumPlasmaLine[col] = spectrumPlasmaLine[col] / specPlasmaSize;
2023-06-01 16:57:44 +00:00
}
} else if (underlayMode == underlayPeakBuffer){
// peak mode, running peak display
for(int col=0; col < spectWidth; col++)
{
2024-05-19 20:21:09 +00:00
spectrumPlasmaLine[col] = spectrumPlasma[0][col]; // initial value
2023-06-01 16:57:44 +00:00
for(int pos=0; pos < specPlasmaSize; pos++)
{
2024-08-13 12:19:50 +00:00
if((double)((quint8)spectrumPlasma[pos][col]) > spectrumPlasmaLine[col])
spectrumPlasmaLine[col] = (quint8)spectrumPlasma[pos][col];
2023-06-01 16:57:44 +00:00
}
}
}
}
2023-06-05 08:27:37 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::showHideControls(spectrumMode_t mode)
2023-06-05 08:27:37 +00:00
{
2025-01-14 13:35:14 +00:00
if(currentScopeMode == mode)
{
return;
}
2025-01-17 00:43:57 +00:00
2025-01-14 13:35:14 +00:00
if (!rigCaps->hasSpectrum) {
2024-04-21 16:50:42 +00:00
spectrum->hide();
waterfall->hide();
splitter->hide();
scopeModeCombo->hide();
edgeCombo->hide();
edgeButton->hide();
holdButton->hide();
toFixedButton->hide();
spanCombo->hide();
clearPeaksButton->hide();
2025-01-14 13:35:14 +00:00
}
else
{
2024-04-21 17:06:49 +00:00
spectrum->show();
waterfall->show();
splitter->show();
scopeModeCombo->show();
clearPeaksButton->show();
2025-01-14 13:35:14 +00:00
switch (mode)
{
case spectModeCenter:
case spectModeScrollC:
edgeCombo->hide();
edgeButton->hide();
toFixedButton->show();
spanCombo->show();
break;
case spectModeFixed:
case spectModeScrollF:
toFixedButton->hide();
spanCombo->hide();
edgeCombo->show();
edgeButton->show();
break;
case spectModeUnknown:
break;
}
2023-06-05 08:27:37 +00:00
}
2025-01-14 13:35:14 +00:00
detachButton->show();
2025-01-17 00:43:57 +00:00
2025-02-10 01:28:22 +00:00
if (rigCaps->hasSpectrum || rigCaps->commands.contains(funcIFShift) || rigCaps->commands.contains(funcPBTInner))
{
confButton->show();
}
else {
confButton->hide();
}
configSpeed->setEnabled(rigCaps->hasSpectrum);
configBottom->setEnabled(rigCaps->hasSpectrum);
configLength->setEnabled(rigCaps->hasSpectrum);
configRef->setEnabled(rigCaps->hasSpectrum);
configScopeEnabled->setEnabled(rigCaps->hasSpectrum);
configTheme->setEnabled(rigCaps->hasSpectrum);
configPbtInner->setEnabled(rigCaps->commands.contains(funcPBTInner));
configPbtOuter->setEnabled(rigCaps->commands.contains(funcPBTOuter));
configIfShift->setEnabled(rigCaps->commands.contains(funcIFShift) || rigCaps->commands.contains(funcPBTInner));
2025-02-10 00:41:11 +00:00
filterCombo->setVisible(rigCaps->filters.size());
2025-02-10 01:28:22 +00:00
dataCombo->setVisible(rigCaps->inputs.size());
2023-06-05 08:27:37 +00:00
}
2025-02-10 01:28:22 +00:00
2025-01-17 00:43:57 +00:00
void receiverWidget::displayScope(bool en)
2023-06-11 21:31:32 +00:00
{
2025-01-23 10:39:35 +00:00
this->splitter->setVisible(en || rigCaps->hasCommand29);
2023-06-11 21:31:32 +00:00
// Hide these controls if disabled
if (!en) {
this->edgeCombo->setVisible(en);
this->edgeButton->setVisible(en);
this->toFixedButton->setVisible(en);
this->spanCombo->setVisible(en);
2025-01-23 10:39:35 +00:00
QTimer::singleShot(0, [this]{
this->resize(this->minimumSizeHint());
});
2023-06-11 21:31:32 +00:00
}
2025-02-10 01:28:22 +00:00
this->clearPeaksButton->setVisible(en && rigCaps->hasSpectrum);
2024-12-31 18:38:43 +00:00
this->holdButton->setVisible(en && rigCaps->commands.contains(funcScopeHold));
2023-06-11 21:31:32 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setScopeMode(spectrumMode_t m)
2023-06-05 08:27:37 +00:00
{
2024-07-13 11:26:47 +00:00
if (m != currentScopeMode) {
scopeModeCombo->blockSignals(true);
scopeModeCombo->setCurrentIndex(scopeModeCombo->findData(m));
scopeModeCombo->blockSignals(false);
showHideControls(m);
2025-01-14 13:35:14 +00:00
currentScopeMode = m;
2024-07-13 11:26:47 +00:00
}
2023-06-05 08:27:37 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setSpan(centerSpanData s)
2023-06-05 08:27:37 +00:00
{
spanCombo->blockSignals(true);
spanCombo->setCurrentIndex(spanCombo->findText(s.name));
spanCombo->blockSignals(false);
}
2025-01-06 23:10:11 +00:00
void receiverWidget::updatedMode(int index)
2023-06-05 08:27:37 +00:00
{
Q_UNUSED(index) // We don't know where it came from!
modeInfo mi = modeCombo->currentData().value<modeInfo>();
mi.filter = filterCombo->currentData().toInt();
2024-01-28 09:42:50 +00:00
if (mi.mk == modeCW || mi.mk == modeCW_R || mi.mk == modeRTTY || mi.mk == modeRTTY_R || mi.mk == modePSK || mi.mk == modePSK_R)
{
mi.data = 0;
dataCombo->setEnabled(false);
} else {
mi.data = dataCombo->currentIndex();
dataCombo->setEnabled(true);
}
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(t.modeFunc,QVariant::fromValue<modeInfo>(mi),false,t.receiver));
2025-01-10 21:36:05 +00:00
if (t.modeFunc == funcModeSet) {
queue->addUnique(priorityImmediate,queueItem(funcDataModeWithFilter,QVariant::fromValue(mi),false,t.receiver));
}
2025-03-02 09:17:52 +00:00
// Request current filtershape/roofing
2025-03-07 10:18:16 +00:00
if (rigCaps->manufacturer == manufIcom)
{
2025-03-02 10:21:49 +00:00
queue->addUnique(priorityHighest,funcFilterShape,false,t.receiver);
queue->addUnique(priorityHighest,funcRoofingFilter,false,t.receiver);
}
2023-06-05 08:27:37 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setEdge(uchar index)
2023-06-05 08:27:37 +00:00
{
edgeCombo->blockSignals(true);
2025-02-19 15:13:08 +00:00
edgeCombo->setCurrentIndex(edgeCombo->findData(index));
edgeCombo->blockSignals(false);
2023-06-05 08:27:37 +00:00
}
2025-03-02 09:17:52 +00:00
void receiverWidget::setRoofing(uchar index)
{
roofingCombo->blockSignals(true);
roofingCombo->setCurrentIndex(roofingCombo->findData(index));
roofingCombo->blockSignals(false);
}
void receiverWidget::setFilterShape(uchar index)
{
filterShapeCombo->blockSignals(true);
filterShapeCombo->setCurrentIndex(filterShapeCombo->findData(index));
filterShapeCombo->blockSignals(false);
}
2025-01-06 23:10:11 +00:00
void receiverWidget::toFixedPressed()
2023-06-05 08:27:37 +00:00
{
int currentEdge = edgeCombo->currentIndex();
bool dialogOk = false;
bool numOk = false;
QStringList edges;
edges << "1" << "2" << "3" << "4";
QString item = QInputDialog::getItem(this, "Select Edge", "Edge to replace:", edges, currentEdge, false, &dialogOk);
if(dialogOk)
{
int edge = QString(item).toInt(&numOk,10);
if(numOk)
{
edgeCombo->blockSignals(true);
2025-02-19 15:13:08 +00:00
edgeCombo->setCurrentIndex(edgeCombo->findData(edge));
2023-06-05 08:27:37 +00:00
edgeCombo->blockSignals(false);
2024-12-31 18:38:43 +00:00
queue->addUnique(priorityImmediate,queueItem(funcScopeSpeed,QVariant::fromValue(spectrumBounds(lowerFreq, upperFreq, edge)),false,receiver));
queue->addUnique(priorityImmediate,queueItem(funcScopeSpeed,QVariant::fromValue<uchar>(spectrumMode_t::spectModeFixed),false,receiver));
2023-06-05 08:27:37 +00:00
}
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::customSpanPressed()
2023-06-05 08:27:37 +00:00
{
2025-02-04 21:30:56 +00:00
float maxSpan = 0.0;
float minSpan = 1.0;
for (const auto &span: rigCaps->scopeCenterSpans)
{
if (double(span.freq / 1000000.0) > maxSpan)
maxSpan = double(span.freq / 1000000.0);
if (double(span.freq / 1000000.0) < minSpan)
minSpan = double(span.freq / 1000000.0);
}
maxSpan = maxSpan * 2;
minSpan = minSpan * 2;
QDialog* dialog = new QDialog(this);
2025-02-09 09:37:16 +00:00
dialog->setToolTip(tr("Please enter the lower and upper frequencies (in MHz) for the currently selected Scope Fixed edge"));
2025-02-04 21:30:56 +00:00
dialog->setWindowTitle(tr("Scope Edges"));
QVBoxLayout* layout = new QVBoxLayout(dialog);
layout->setSizeConstraint(QLayout::SetFixedSize);
QHBoxLayout* header = new QHBoxLayout();
layout->addLayout(header);
QLabel* lowLabel = new QLabel();
2025-02-09 09:37:16 +00:00
lowLabel->setText(tr("Start Freq (MHz)"));
2025-02-04 21:30:56 +00:00
lowLabel->setAlignment(Qt::AlignCenter);
header->addWidget(lowLabel);
QLabel* highLabel = new QLabel();
2025-02-09 09:37:16 +00:00
highLabel->setText(tr("End Freq (MHz)"));
2025-02-04 21:30:56 +00:00
highLabel->setAlignment(Qt::AlignCenter);
header->addWidget(highLabel);
QHBoxLayout* spins = new QHBoxLayout();
layout->addLayout(spins);
QDoubleSpinBox* low = new QDoubleSpinBox();
low->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding);
low->setValue(lowerFreq);
low->setDecimals(3);
low->setSingleStep(minSpan);
low->setRange(minFreqMhz,maxFreqMhz);
low->setAlignment(Qt::AlignCenter);
2025-02-09 09:37:16 +00:00
low->setToolTip(tr("Fixed edge start frequency"));
2025-02-04 21:30:56 +00:00
spins->addWidget(low);
low->setMinimumHeight(low->minimumSizeHint().height()*2);
QDoubleSpinBox* high = new QDoubleSpinBox();
high->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding);
high->setValue(upperFreq);
high->setDecimals(3);
high->setSingleStep(minSpan);
high->setMinimumHeight(high->minimumSizeHint().height()*2);
high->setRange(minFreqMhz,maxFreqMhz);
high->setAlignment(Qt::AlignCenter);
2025-02-09 09:37:16 +00:00
high->setToolTip(tr("Fixed edge end frequency"));
2025-02-04 21:30:56 +00:00
spins->addWidget(high);
QHBoxLayout* buttons = new QHBoxLayout();
layout->addLayout(buttons);
QPushButton *ok = new QPushButton("OK");
QPushButton *cancel = new QPushButton("Cancel");
buttons->addWidget(ok);
buttons->addWidget(cancel);
connect(ok, &QPushButton::clicked, this, [=]() {
// Here we need to attempt to update the fixed edge
if (high->value() - low->value() > maxSpan)
{
high->setValue(low->value()+maxSpan);
}
else if (high->value() < low->value() || high->value() - low->value() < minSpan)
{
high->setValue(low->value()+minSpan);
}
else
{
2025-02-19 15:13:08 +00:00
qDebug(logGui()) << "setting edge to: " << low->value() << ", " << high->value() << ", edge num: " << edgeCombo->currentData().toUInt();
queue->addUnique(priorityImmediate,queueItem(funcScopeFixedEdgeFreq,QVariant::fromValue(spectrumBounds(low->value(), high->value(), edgeCombo->currentData().toUInt())),false,receiver));
2025-02-04 21:30:56 +00:00
dialog->close();
}
});
connect(cancel, &QPushButton::clicked, this, [=]() {
dialog->close();
});
dialog->exec();
2023-06-05 08:27:37 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::doubleClick(QMouseEvent *me)
2023-06-05 08:27:37 +00:00
{
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
2023-06-05 08:27:37 +00:00
if (me->button() == Qt::LeftButton)
{
double x;
freqt freqGo;
2025-02-09 16:46:18 +00:00
if (!freqLock)
2023-06-05 08:27:37 +00:00
{
//y = plot->yAxis->pixelToCoord(me->pos().y());
x = spectrum->xAxis->pixelToCoord(me->pos().x());
freqGo.Hz = x * 1E6;
freqGo.Hz = roundFrequency(freqGo.Hz, stepSize);
freqGo.MHzDouble = (float)freqGo.Hz / 1E6;
2025-01-01 13:40:58 +00:00
emit sendTrack(freqGo.Hz-this->freq.Hz);
2023-09-26 17:46:04 +00:00
setFrequency(freqGo);
queue->addUnique(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(freqGo),false,t.receiver));
2023-06-05 08:27:37 +00:00
}
}
else if (me->button() == Qt::RightButton)
{
QCPAbstractItem* item = spectrum->itemAt(me->pos(), true);
double pbFreq = (pbtDefault / passbandWidth) * 127.0;
2024-10-24 12:08:15 +00:00
qint16 newFreq = pbFreq + 128;
queue->addUnique(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue<ushort>(newFreq),false,t.receiver));
queue->addUnique(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue<ushort>(newFreq),false,t.receiver));
2023-06-05 08:27:37 +00:00
QCPItemRect* rectItem = dynamic_cast<QCPItemRect*> (item);
if (rectItem != nullptr)
{
2024-10-24 12:08:15 +00:00
2023-06-05 08:27:37 +00:00
}
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::scopeClick(QMouseEvent* me)
2023-06-05 08:27:37 +00:00
{
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
2023-06-05 08:27:37 +00:00
QCPAbstractItem* item = spectrum->itemAt(me->pos(), true);
2023-06-05 20:08:01 +00:00
QCPItemText* textItem = dynamic_cast<QCPItemText*> (item);
2023-06-05 08:27:37 +00:00
QCPItemRect* rectItem = dynamic_cast<QCPItemRect*> (item);
#if QCUSTOMPLOT_VERSION < 0x020000
int leftPix = (int)passbandIndicator->left->pixelPoint().x();
int rightPix = (int)passbandIndicator->right->pixelPoint().x();
int pbtLeftPix = (int)pbtIndicator->left->pixelPoint().x();
int pbtRightPix = (int)pbtIndicator->right->pixelPoint().x();
#else
int leftPix = (int)passbandIndicator->left->pixelPosition().x();
int rightPix = (int)passbandIndicator->right->pixelPosition().x();
int pbtLeftPix = (int)pbtIndicator->left->pixelPosition().x();
int pbtRightPix = (int)pbtIndicator->right->pixelPosition().x();
#endif
int pbtCenterPix = pbtLeftPix + ((pbtRightPix - pbtLeftPix) / 2);
int cursor = me->pos().x();
if (me->button() == Qt::LeftButton) {
2023-06-05 20:08:01 +00:00
this->mousePressFreq = spectrum->xAxis->pixelToCoord(cursor);
2023-06-05 08:27:37 +00:00
if (textItem != nullptr)
{
QMap<QString, spotData*>::iterator spot = clusterSpots.find(textItem->text());
2025-02-09 16:46:18 +00:00
if (spot != clusterSpots.end() && spot.key() == textItem->text() && !freqLock)
2023-06-05 08:27:37 +00:00
{
qInfo(logGui()) << "Clicked on spot:" << textItem->text();
freqt freqGo;
freqGo.Hz = (spot.value()->frequency) * 1E6;
freqGo.MHzDouble = spot.value()->frequency;
2025-01-01 13:40:58 +00:00
emit sendTrack(freqGo.Hz-this->freq.Hz);
2023-09-26 17:46:04 +00:00
setFrequency(freqGo);
queue->add(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(freqGo),false,t.receiver));
2025-01-01 13:40:58 +00:00
2023-06-05 08:27:37 +00:00
}
}
2023-06-05 20:08:01 +00:00
else if (passbandAction == passbandStatic && rectItem != nullptr)
2023-06-05 08:27:37 +00:00
{
if ((cursor <= leftPix && cursor > leftPix - 10) || (cursor >= rightPix && cursor < rightPix + 10))
{
passbandAction = passbandResizing;
}
}
// TODO clickdragtuning and sending messages to statusbar
2023-06-08 07:20:50 +00:00
else if (clickDragTuning)
2023-06-05 08:27:37 +00:00
{
2024-04-30 08:42:54 +00:00
emit showStatusBarText(QString("Selected %1 MHz").arg(this->mousePressFreq));
2023-06-05 08:27:37 +00:00
}
else {
2024-04-30 08:42:54 +00:00
emit showStatusBarText(QString("Selected %1 MHz").arg(this->mousePressFreq));
}
2023-06-08 07:20:50 +00:00
2023-06-05 08:27:37 +00:00
}
else if (me->button() == Qt::RightButton)
{
if (textItem != nullptr) {
QMap<QString, spotData*>::iterator spot = clusterSpots.find(textItem->text());
if (spot != clusterSpots.end() && spot.key() == textItem->text()) {
// parent and children are destroyed on close
QDialog* spotDialog = new QDialog();
QVBoxLayout* vlayout = new QVBoxLayout;
//spotDialog->setFixedSize(240, 100);
spotDialog->setBaseSize(1, 1);
spotDialog->setWindowTitle(spot.value()->dxcall);
QLabel* dxcall = new QLabel(QString("DX:%1").arg(spot.value()->dxcall));
QLabel* spotter = new QLabel(QString("Spotter:%1").arg(spot.value()->spottercall));
QLabel* frequency = new QLabel(QString("Frequency:%1 MHz").arg(spot.value()->frequency));
QLabel* comment = new QLabel(QString("Comment:%1").arg(spot.value()->comment));
QAbstractButton* bExit = new QPushButton("Close");
vlayout->addWidget(dxcall);
vlayout->addWidget(spotter);
vlayout->addWidget(frequency);
vlayout->addWidget(comment);
vlayout->addWidget(bExit);
spotDialog->setLayout(vlayout);
spotDialog->show();
spotDialog->connect(bExit, SIGNAL(clicked()), spotDialog, SLOT(close()));
}
}
else if (passbandAction == passbandStatic && rectItem != nullptr)
2023-06-05 08:27:37 +00:00
{
if (cursor <= pbtLeftPix && cursor > pbtLeftPix - 10)
{
passbandAction = pbtInnerMove;
}
else if (cursor >= pbtRightPix && cursor < pbtRightPix + 10)
{
passbandAction = pbtOuterMove;
}
else if (cursor > pbtCenterPix - 20 && cursor < pbtCenterPix + 20)
{
passbandAction = pbtMoving;
}
this->mousePressFreq = spectrum->xAxis->pixelToCoord(cursor);
}
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::scopeMouseRelease(QMouseEvent* me)
2023-06-05 08:27:37 +00:00
{
2023-06-08 07:20:50 +00:00
2023-06-05 08:27:37 +00:00
QCPAbstractItem* item = spectrum->itemAt(me->pos(), true);
QCPItemText* textItem = dynamic_cast<QCPItemText*> (item);
2023-06-08 07:20:50 +00:00
if (textItem == nullptr && clickDragTuning) {
this->mouseReleaseFreq = spectrum->xAxis->pixelToCoord(me->pos().x());
2023-06-05 08:27:37 +00:00
double delta = mouseReleaseFreq - mousePressFreq;
qInfo(logGui()) << "Mouse release delta: " << delta;
}
2023-06-08 07:20:50 +00:00
2023-06-05 08:27:37 +00:00
if (passbandAction != passbandStatic) {
passbandAction = passbandStatic;
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::scopeMouseMove(QMouseEvent* me)
2023-06-05 08:27:37 +00:00
{
QCPAbstractItem* item = spectrum->itemAt(me->pos(), true);
QCPItemText* textItem = dynamic_cast<QCPItemText*> (item);
QCPItemRect* rectItem = dynamic_cast<QCPItemRect*> (item);
#if QCUSTOMPLOT_VERSION < 0x020000
int leftPix = (int)passbandIndicator->left->pixelPoint().x();
int rightPix = (int)passbandIndicator->right->pixelPoint().x();
int pbtLeftPix = (int)pbtIndicator->left->pixelPoint().x();
int pbtRightPix = (int)pbtIndicator->right->pixelPoint().x();
#else
int leftPix = (int)passbandIndicator->left->pixelPosition().x();
int rightPix = (int)passbandIndicator->right->pixelPosition().x();
int pbtLeftPix = (int)pbtIndicator->left->pixelPosition().x();
int pbtRightPix = (int)pbtIndicator->right->pixelPosition().x();
#endif
int pbtCenterPix = pbtLeftPix + ((pbtRightPix - pbtLeftPix) / 2);
int cursor = me->pos().x();
double movedFrequency = spectrum->xAxis->pixelToCoord(cursor) - mousePressFreq;
if (passbandAction == passbandStatic && rectItem != nullptr)
{
if ((cursor <= leftPix && cursor > leftPix - 10) ||
(cursor >= rightPix && cursor < rightPix + 10) ||
(cursor <= pbtLeftPix && cursor > pbtLeftPix - 10) ||
(cursor >= pbtRightPix && cursor < pbtRightPix + 10))
{
setCursor(Qt::SizeHorCursor);
}
else if (cursor > pbtCenterPix - 20 && cursor < pbtCenterPix + 20) {
setCursor(Qt::OpenHandCursor);
}
}
else if (passbandAction == passbandResizing)
{
2023-06-05 20:08:01 +00:00
static double lastFreq = movedFrequency;
if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) {
2023-06-05 08:27:37 +00:00
2023-06-05 20:08:01 +00:00
// We are currently resizing the passband.
double pb = 0.0;
double origin = passbandCenterFrequency;
if (mode.mk == modeLSB)
{
origin = - passbandCenterFrequency;
}
2023-06-05 08:27:37 +00:00
2023-06-05 20:08:01 +00:00
if (spectrum->xAxis->pixelToCoord(cursor) >= freq.MHzDouble + origin) {
pb = spectrum->xAxis->pixelToCoord(cursor) - passbandIndicator->topLeft->coords().x();
}
else {
pb = passbandIndicator->bottomRight->coords().x() - spectrum->xAxis->pixelToCoord(cursor);
}
if (mode.bwMax != 0 && mode.bwMin != 0) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcFilterWidth,QVariant::fromValue<ushort>(pb * 1000000),false,t.receiver));
}
2023-06-05 20:08:01 +00:00
//qInfo() << "New passband" << uint(pb * 1000000);
lastFreq = movedFrequency;
2023-06-05 08:27:37 +00:00
}
}
else if (passbandAction == pbtMoving) {
//qint16 shift = (qint16)(level - 128);
//TPBFInner = (double)(shift / 127.0) * (passbandWidth);
// Only move if more than 100Hz
static double lastFreq = movedFrequency;
if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) {
double innerFreq = ((double)(PBTInner + movedFrequency) / passbandWidth) * 127.0;
double outerFreq = ((double)(PBTOuter + movedFrequency) / passbandWidth) * 127.0;
qint16 newInFreq = innerFreq + 128;
qint16 newOutFreq = outerFreq + 128;
if (newInFreq >= 0 && newInFreq <= 255 && newOutFreq >= 0 && newOutFreq <= 255 && mode.bwMax != 0)
{
2023-06-05 08:27:37 +00:00
qDebug() << QString("Moving passband by %1 Hz (Inner %2) (Outer %3) Mode:%4").arg((qint16)(movedFrequency * 1000000))
.arg(newInFreq).arg(newOutFreq).arg(mode.mk);
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue<ushort>(newInFreq),false,t.receiver));
queue->addUnique(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue<ushort>(newInFreq),false,t.receiver));
2023-06-05 08:27:37 +00:00
}
lastFreq = movedFrequency;
}
}
else if (passbandAction == pbtInnerMove) {
static double lastFreq = movedFrequency;
if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) {
double pbFreq = ((double)(PBTInner + movedFrequency) / passbandWidth) * 127.0;
qint16 newFreq = pbFreq + 128;
if (newFreq >= 0 && newFreq <= 255 && mode.bwMax != 0) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcPBTInner,QVariant::fromValue<ushort>(newFreq),false,t.receiver));
2023-06-05 08:27:37 +00:00
}
lastFreq = movedFrequency;
}
}
else if (passbandAction == pbtOuterMove) {
static double lastFreq = movedFrequency;
if (lastFreq - movedFrequency > 0.000049 || movedFrequency - lastFreq > 0.000049) {
double pbFreq = ((double)(PBTOuter + movedFrequency) / passbandWidth) * 127.0;
qint16 newFreq = pbFreq + 128;
if (newFreq >= 0 && newFreq <= 255 && mode.bwMax != 0) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcPBTOuter,QVariant::fromValue<ushort>(newFreq),false,t.receiver));
2023-06-05 08:27:37 +00:00
}
lastFreq = movedFrequency;
}
}
2025-02-09 16:46:18 +00:00
else if (passbandAction == passbandStatic && me->buttons() == Qt::LeftButton && textItem == nullptr && clickDragTuning )
2023-06-05 08:27:37 +00:00
{
2023-06-08 07:20:50 +00:00
double delta = spectrum->xAxis->pixelToCoord(cursor) - mousePressFreq;
2023-06-05 08:27:37 +00:00
qDebug(logGui()) << "Mouse moving delta: " << delta;
2025-02-09 16:46:18 +00:00
if( (( delta < -0.0001 ) || (delta > 0.0001)) && ((delta < 0.501) && (delta > -0.501)) && !freqLock)
2023-06-05 08:27:37 +00:00
{
freqt freqGo;
freqGo.Hz = (freq.MHzDouble + delta) * 1E6;
2023-06-08 07:20:50 +00:00
freqGo.Hz = roundFrequency(freqGo.Hz, stepSize);
2023-06-05 08:27:37 +00:00
freqGo.MHzDouble = (float)freqGo.Hz / 1E6;
2025-01-01 13:40:58 +00:00
emit sendTrack(freqGo.Hz-this->freq.Hz);
2023-09-26 17:46:04 +00:00
setFrequency(freqGo);
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->add(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(freqGo),false,t.receiver));
2023-06-05 08:27:37 +00:00
}
}
else {
setCursor(Qt::ArrowCursor);
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::waterfallClick(QMouseEvent *me)
2023-06-05 08:27:37 +00:00
{
2023-06-08 07:20:50 +00:00
double x = spectrum->xAxis->pixelToCoord(me->pos().x());
emit showStatusBarText(QString("Selected %1 MHz").arg(x));
2023-06-05 08:27:37 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::scroll(QWheelEvent *we)
2023-06-05 08:27:37 +00:00
{
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
// angleDelta is supposed to be eights of a degree of mouse wheel rotation
2023-09-25 17:03:31 +00:00
int deltaY = we->angleDelta().y();
int deltaX = we->angleDelta().x();
int delta = (deltaX==0)?deltaY:deltaX;
//qreal offset = qreal(delta) / qreal((deltaX==0)?scrollYperClick:scrollXperClick);
2023-09-25 17:03:31 +00:00
//qreal offset = qreal(delta) / 120;
qreal numDegrees = delta / 8;
qreal offset = numDegrees / 15;
2023-09-25 17:03:31 +00:00
qreal stepsToScroll = QApplication::wheelScrollLines() * offset;
// Did we change direction?
if( (scrollWheelOffsetAccumulated > 0) && (offset > 0) ) {
scrollWheelOffsetAccumulated += stepsToScroll;
} else if ((scrollWheelOffsetAccumulated < 0) && (offset < 0)) {
scrollWheelOffsetAccumulated += stepsToScroll;
} else {
// Changed direction, zap the old accumulation:
scrollWheelOffsetAccumulated = stepsToScroll;
//qInfo() << "Scroll changed direction";
2023-09-25 17:03:31 +00:00
}
int clicks = int(scrollWheelOffsetAccumulated);
2023-06-05 08:27:37 +00:00
if (!clicks) {
2023-09-25 17:03:31 +00:00
// qInfo() << "Rejecting minor scroll motion, too small. Wheel Clicks: " << clicks << ", angleDelta: " << delta;
2025-02-18 21:36:49 +00:00
// qInfo() << "Accumulator value: " << scrollWheelOffsetAccumulated;
2023-09-25 17:03:31 +00:00
// qInfo() << "stepsToScroll: " << stepsToScroll;
// qInfo() << "Storing scroll motion for later use.";
2023-06-05 08:27:37 +00:00
return;
2023-09-25 17:03:31 +00:00
} else {
// qInfo() << "Accepted scroll motion. Wheel Clicks: " << clicks << ", angleDelta: " << delta;
2025-02-18 21:36:49 +00:00
// qInfo() << "Accumulator value: " << scrollWheelOffsetAccumulated;
2023-09-25 17:03:31 +00:00
// qInfo() << "stepsToScroll: " << stepsToScroll;
}
2023-06-05 08:27:37 +00:00
2023-09-25 17:03:31 +00:00
// If we made it this far, it's time to scroll and to ultimately
// clear the scroll accumulator.
2023-06-05 08:27:37 +00:00
unsigned int stepsHz = stepSize;
Qt::KeyboardModifiers key = we->modifiers();
if ((key == Qt::ShiftModifier) && (stepsHz != 1))
{
stepsHz /= 10;
}
else if (key == Qt::ControlModifier)
{
stepsHz *= 10;
}
2025-02-09 16:46:18 +00:00
if (!freqLock) {
2023-06-05 08:27:37 +00:00
freqt f;
f.Hz = roundFrequency(freq.Hz, clicks, stepsHz);
f.MHzDouble = f.Hz / (double)1E6;
emit sendTrack(f.Hz-this->freq.Hz); // Where does this go?
2023-06-05 08:27:37 +00:00
setFrequencyLocally(f);
2025-02-09 16:46:18 +00:00
queue->add(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(f),false,receiver));
tempLockAcceptFreqData();
2025-02-09 16:46:18 +00:00
//qInfo() << "Moving to freq:" << f.Hz << "step" << stepsHz;
}
2023-09-25 17:03:31 +00:00
scrollWheelOffsetAccumulated = 0;
2023-06-05 08:27:37 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::receiveMode(modeInfo m, uchar vfo)
2023-06-05 08:27:37 +00:00
{
// Update mode information if mode/filter/data has changed.
// Not all rigs send data so this "might" need to be updated independantly?
if (vfo > 0) {
if (m.mk != modeUnknown)
unselectedMode=m;
return;
2024-12-31 18:38:43 +00:00
}
2025-01-14 13:35:14 +00:00
if (m.filter != 0xff && this->mode.filter != m.filter)
{
filterCombo->blockSignals(true);
filterCombo->setCurrentIndex(filterCombo->findData(m.filter));
filterCombo->blockSignals(false);
mode.filter=m.filter;
}
if (m.data != 0xff && this->mode.data != m.data)
2023-06-05 08:27:37 +00:00
{
emit dataChanged(m); // Signal wfmain that the data mode has been changed.
dataCombo->blockSignals(true);
dataCombo->setCurrentIndex(m.data);
dataCombo->blockSignals(false);
mode.data=m.data;
}
if (m.mk != modeUnknown && mode.mk != m.mk) {
2025-01-06 14:43:14 +00:00
qInfo(logSystem()) << __func__ << QString("Received new mode for %0: %1 (%2) filter:%3 data:%4")
.arg((receiver?"Sub":"Main")).arg(QString::number(m.mk,16)).arg(m.name).arg(m.filter).arg(m.data) ;
2023-06-05 08:27:37 +00:00
if (this->mode.mk != m.mk) {
for (int i=0;i<modeCombo->count();i++)
{
modeInfo mi = modeCombo->itemData(i).value<modeInfo>();
if (mi.mk == m.mk)
2023-06-05 08:27:37 +00:00
{
modeCombo->blockSignals(true);
modeCombo->setCurrentIndex(i);
modeCombo->blockSignals(false);
break;
2023-06-05 08:27:37 +00:00
}
}
}
2024-01-28 09:42:50 +00:00
if (m.mk == modeCW || m.mk == modeCW_R || m.mk == modeRTTY || m.mk == modeRTTY_R || m.mk == modePSK || m.mk == modePSK_R)
{
dataCombo->setEnabled(false);
} else {
dataCombo->setEnabled(true);
}
2025-01-14 13:35:14 +00:00
if (m.mk != mode.mk) {
2023-06-05 20:08:01 +00:00
// We have changed mode so "may" need to change regular commands
2023-06-05 20:08:01 +00:00
passbandCenterFrequency = 0.0;
2023-06-05 08:27:37 +00:00
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,false);
2025-01-14 13:35:14 +00:00
// Make sure the filterWidth range is within limits.
// If new mode doesn't allow bandwidth control, disable filterwidth and pbt.
2025-01-14 13:35:14 +00:00
configFilterWidth->blockSignals(true);
configFilterWidth->setRange(m.bwMin,m.bwMax);
configFilterWidth->setValue(m.bwMax);
configFilterWidth->blockSignals(false);
2025-01-14 13:35:14 +00:00
if (m.bwMin > 0 || m.bwMax > 0) {
// Set config specific options)
if (rigCaps->manufacturer == manufKenwood)
{
if (m.mk == modeCW || m.mk == modeCW_R || m.mk == modePSK || m.mk == modePSK_R) {
queue->addUnique(priorityHigh,funcFilterWidth,true,t.receiver);
queue->del(funcPBTInner,t.receiver);
queue->del(funcPBTOuter,t.receiver);
configPbtInner->setEnabled(false);
configPbtOuter->setEnabled(false);
configIfShift->setEnabled(false);
2025-01-30 11:47:05 +00:00
//configFilterWidth->setEnabled(true);
2025-01-14 13:35:14 +00:00
}
else if (m.mk == modeUSB || m.mk == modeLSB || m.mk == modeAM || m.mk == modeFM) {
queue->addUnique(priorityHigh,funcPBTInner,true,t.receiver);
queue->addUnique(priorityHigh,funcPBTOuter,true,t.receiver);
queue->del(funcFilterWidth,t.receiver);
2025-02-10 01:28:22 +00:00
configPbtInner->setEnabled(true && rigCaps->commands.contains(funcPBTInner));
configPbtOuter->setEnabled(true && rigCaps->commands.contains(funcPBTOuter));
configIfShift->setEnabled(true && (rigCaps->commands.contains(funcIFShift) || rigCaps->commands.contains(funcPBTInner)));
2025-01-30 11:47:05 +00:00
//configFilterWidth->setEnabled(false);
2025-01-14 13:35:14 +00:00
}
} else
{
queue->addUnique(priorityHigh,funcPBTInner,true,t.receiver);
queue->addUnique(priorityHigh,funcPBTOuter,true,t.receiver);
queue->addUnique(priorityHigh,funcFilterWidth,true,t.receiver);
configPbtInner->setEnabled(true);
configPbtOuter->setEnabled(true);
configFilterWidth->setEnabled(true);
}
} else{
queue->del(funcPBTInner,t.receiver);
queue->del(funcPBTOuter,t.receiver);
queue->del(funcFilterWidth,t.receiver);
configPbtInner->setEnabled(false);
configPbtOuter->setEnabled(false);
2025-01-14 13:35:14 +00:00
configIfShift->setEnabled(false);
configFilterWidth->setEnabled(false);
2024-11-07 18:59:38 +00:00
passbandWidth = double(m.pass/1000000.0);
}
2025-03-10 10:03:06 +00:00
if (m.mk == modeFM)
{
queue->addUnique(priorityMediumHigh,funcToneFreq,true,t.receiver);
queue->addUnique(priorityMediumHigh,funcTSQLFreq,true,t.receiver);
queue->addUnique(priorityMediumHigh,funcRepeaterTone,true,t.receiver);
queue->addUnique(priorityMediumHigh,funcRepeaterTSQL,true,t.receiver);
}
else
{
queue->del(funcToneFreq,t.receiver);
queue->del(funcTSQLFreq,t.receiver);
queue->del(funcRepeaterTone,t.receiver);
queue->del(funcRepeaterTSQL,t.receiver);
}
2024-08-05 12:27:24 +00:00
if (m.mk == modeDD || m.mk == modeDV)
{
t = queue->getVfoCommand(vfoB,receiver,false);
queue->del(t.freqFunc,t.receiver);
queue->del(t.modeFunc,t.receiver);
} else if (queue->getState().vfoMode == vfoModeVfo) {
t = queue->getVfoCommand(vfoB,receiver,false);
queue->addUnique(priorityHigh,t.freqFunc,true,t.receiver);
queue->addUnique(priorityHigh,t.modeFunc,true,t.receiver);
2024-08-05 12:27:24 +00:00
}
if (m.mk == modeCW || m.mk == modeCW_R)
{
queue->addUnique(priorityMediumHigh,funcCwPitch,true,t.receiver);
queue->addUnique(priorityMediumHigh,funcDashRatio,true,t.receiver);
queue->addUnique(priorityMediumHigh,funcKeySpeed,true,t.receiver);
queue->addUnique(priorityMediumHigh,funcBreakIn,true,t.receiver);
2024-08-05 12:27:24 +00:00
} else {
queue->del(funcCwPitch,t.receiver);
queue->del(funcDashRatio,t.receiver);
queue->del(funcKeySpeed,t.receiver);
queue->del(funcBreakIn,t.receiver);
2024-08-05 12:27:24 +00:00
}
2024-02-11 18:00:23 +00:00
#if defined __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
2023-06-05 20:08:01 +00:00
switch (m.mk) {
2024-08-05 12:27:24 +00:00
// M0VSE this needs to be replaced with 1/2 the "actual" width of the RTTY signal+the mark freq.
2023-06-05 20:08:01 +00:00
case modeRTTY:
case modeRTTY_R:
2024-02-11 18:00:23 +00:00
passbandCenterFrequency = 0.00008925;
break;
case modeLSB:
case modeUSB:
2023-06-05 20:08:01 +00:00
case modePSK:
case modePSK_R:
2025-01-30 11:47:05 +00:00
if (rigCaps->manufacturer == manufIcom)
passbandCenterFrequency = 0.0015;
else
passbandCenterFrequency = 0.0;
case modeAM:
2023-06-05 20:08:01 +00:00
case modeCW:
case modeCW_R:
break;
default:
break;
}
2024-02-11 18:00:23 +00:00
#if defined __GNUC__
#pragma GCC diagnostic pop
#endif
2025-01-06 14:43:14 +00:00
}
this->mode = m;
2023-06-05 08:27:37 +00:00
}
}
2025-01-06 23:10:11 +00:00
quint64 receiverWidget::roundFrequency(quint64 frequency, unsigned int tsHz)
2023-06-05 08:27:37 +00:00
{
return roundFrequency(frequency, 0, tsHz);
}
2025-01-06 23:10:11 +00:00
quint64 receiverWidget::roundFrequency(quint64 frequency, int steps, unsigned int tsHz)
2023-06-05 08:27:37 +00:00
{
if(steps > 0)
{
frequency = frequency + (quint64)(steps*tsHz);
} else if (steps < 0) {
frequency = frequency - std::min((quint64)(abs(steps)*tsHz), frequency);
}
quint64 rounded = frequency;
if(tuningFloorZeros)
{
rounded = ((frequency % tsHz) > tsHz/2) ? frequency + tsHz - frequency%tsHz : frequency - frequency%tsHz;
}
return rounded;
}
2025-01-06 23:10:11 +00:00
void receiverWidget::receiveCwPitch(quint16 pitch)
2023-06-05 08:27:37 +00:00
{
2024-12-14 23:36:16 +00:00
if (mode.mk == modeCW || mode.mk == modeCW_R) {
if (pitch != this->cwPitch)
2023-06-05 08:27:37 +00:00
{
2024-12-14 23:36:16 +00:00
passbandCenterFrequency = pitch / 2000000.0;
qDebug(logSystem()) << QString("%0 Received new CW Pitch %1 Hz was %2 (center freq %3 MHz)").arg((receiver?"Sub":"Main")).arg(pitch).arg(cwPitch).arg(passbandCenterFrequency);
this->cwPitch = pitch;
2023-06-05 08:27:37 +00:00
}
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::receivePassband(quint16 pass)
2023-06-05 08:27:37 +00:00
{
double pb = (double)(pass / 1000000.0);
if (passbandWidth != pb) {
passbandWidth = pb;
//trxadj->updatePassband(pass);
qDebug(logSystem()) << QString("%0 Received new IF Filter/Passband %1 Hz").arg(receiver?"Sub":"Main").arg(pass);
emit showStatusBarText(QString("%0 IF filter width %1 Hz (%2 MHz)").arg(receiver?"Sub":"Main").arg(pass).arg(passbandWidth));
2024-07-26 23:12:25 +00:00
configFilterWidth->blockSignals(true);
configFilterWidth->setValue(pass);
configFilterWidth->blockSignals(false);
2023-06-05 08:27:37 +00:00
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::selected(bool en)
{
2024-02-10 19:54:39 +00:00
isActive = en;
2025-01-23 10:39:35 +00:00
// Hide scope if we are not selected and don't have command 29.
this->displayScope(en || rigCaps->hasCommand29);
this->setEnabled(en || rigCaps->hasCommand29);
// If this scope is not visible set to visible if selected.
this->setVisible(en || this->isVisible());
if (en)
{
2023-09-25 13:55:27 +00:00
this->setStyleSheet("QGroupBox { border:1px solid red;}");
}
else
{
2023-09-25 13:55:27 +00:00
this->setStyleSheet(defaultStyleSheet);
2024-12-31 18:38:43 +00:00
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setHold(bool h)
{
this->holdButton->blockSignals(true);
this->holdButton->setChecked(h);
this->holdButton->blockSignals(false);
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setSpeed(uchar s)
{
2023-07-16 09:08:28 +00:00
this->currentSpeed = s;
2023-09-25 13:55:27 +00:00
configSpeed->setCurrentIndex(configSpeed->findData(currentSpeed));
}
2025-01-06 23:10:11 +00:00
void receiverWidget::receiveSpots(uchar receiver, QList<spotData> spots)
{
if (receiver != this->receiver) {
2024-01-28 13:14:47 +00:00
return;
}
//QElapsedTimer timer;
//timer.start();
bool current = false;
if (clusterSpots.size() > 0) {
current=clusterSpots.begin().value()->current;
}
for(const auto &s: spots)
{
bool found = false;
QMap<QString, spotData*>::iterator spot = clusterSpots.find(s.dxcall);
while (spot != clusterSpots.end() && spot.key() == s.dxcall && spot.value()->frequency == s.frequency) {
spot.value()->current = !current;
found = true;
++spot;
}
if (!found)
{
QCPRange xrange=spectrum->xAxis->range();
QCPRange yrange=spectrum->yAxis->range();
double left = s.frequency;
double top = yrange.upper-2.0;
spotData* sp = new spotData(s);
sp->current = !current;
sp->text = new QCPItemText(spectrum);
sp->text->setAntialiased(true);
sp->text->setColor(colors.clusterSpots);
sp->text->setText(sp->dxcall);
sp->text->setFont(QFont(font().family(), 10));
sp->text->setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
sp->text->position->setType(QCPItemPosition::ptPlotCoords);
//QMargins margin;
//int width = (sp->text->right - sp->text->left) / 8;
//margin.setLeft(width);
//margin.setRight(width);
//sp->text->setPadding(margin);
sp->text->position->setCoords(left, top);
qDebug(logCluster()) << "ADD:" << sp->dxcall;
bool conflict = true;
while (conflict) {
#if QCUSTOMPLOT_VERSION < 0x020000
QCPItemText* item = dynamic_cast<QCPItemText*>(spectrum->itemAt(QPointF(spectrum->xAxis->coordToPixel(left),spectrum->yAxis->coordToPixel(top)), true));
#else
QCPItemText* item = dynamic_cast<QCPItemText*>(spectrum->itemAt(QPointF(spectrum->xAxis->coordToPixel(left),spectrum->yAxis->coordToPixel(top)), true));
#endif
//QCPItemText* item = dynamic_cast<QCPItemText*> (absitem);
if (item != nullptr) {
//qInfo() << "Spot found at top:" << top << "left:" << left << "(" << spectrum->xAxis->coordToPixel(top) <<"," << spectrum->xAxis->coordToPixel(left) << ") spot:" << item->text();
top = top - 5.0;
if (top < 10.0)
{
top = yrange.upper-2.0;
left = left + (xrange.size()/20);
}
}
else {
conflict = false;
}
}
sp->text->position->setCoords(left, top);
sp->text->setSelectable(true);
sp->text->setVisible(true);
clusterSpots.insert(sp->dxcall, sp);
}
}
2024-06-12 16:11:01 +00:00
QMutableMapIterator<QString, spotData *> sp(clusterSpots);
while (sp.hasNext())
{
auto spot = sp.next();
if (spot.value()->current == current) {
spectrum->removeItem(spot.value()->text);
delete spot.value();
sp.remove();
}
}
//qDebug(logCluster()) << "Processing took" << timer.nsecsElapsed() / 1000 << "us";
}
2023-07-16 09:08:28 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::configPressed()
2023-07-16 09:08:28 +00:00
{
2023-09-25 18:21:31 +00:00
this->configGroup->setVisible(!this->configGroup->isVisible());
2023-09-25 18:35:22 +00:00
//QTimer::singleShot(200, this, [this]() {
2023-09-25 18:21:31 +00:00
if (this->configGroup->isVisible())
this->confButton->setText(">");
else
this->confButton->setText("<");
2023-09-25 18:35:22 +00:00
//});
2023-07-16 09:08:28 +00:00
}
void receiverWidget::freqNoteLockTimerSlot() {
this->allowAcceptFreqData = true;
}
void receiverWidget::tempLockAcceptFreqData() {
this->allowAcceptFreqData = false;
frequencyNotificationLockoutTimer->start();
}
2023-07-16 09:08:28 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::wfTheme(int num)
2023-07-16 09:08:28 +00:00
{
2023-07-16 09:46:30 +00:00
currentTheme = QCPColorGradient::GradientPreset(num);
2023-07-16 09:08:28 +00:00
colorMap->setGradient(static_cast<QCPColorGradient::GradientPreset>(num));
2023-09-25 13:55:27 +00:00
configTheme->setCurrentIndex(configTheme->findData(currentTheme));
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setPBTInner (uchar val) {
2025-01-14 13:35:14 +00:00
if (rigCaps->manufacturer == manufKenwood)
2024-02-10 12:11:10 +00:00
{
2025-01-18 12:29:34 +00:00
ushort width=0;
if (this->mode.mk == modeLSB || this->mode.mk == modeUSB)
{
if (val < 25)
width = (val+6) * 100;
else if (val == 25)
width = 3400;
else if (val == 26)
width = 4000;
else if (val == 27)
width = 5000;
}
if (double(width)/1000000.0 != this->PBTInner)
{
this->PBTInner = double(width)/1000000.0;
configPbtInner->blockSignals(true);
configPbtInner->setValue(val);
configPbtInner->blockSignals(false);
}
2025-01-14 13:35:14 +00:00
} else
{
qint16 shift = (qint16)(val - 128);
double tempVar = ceil((shift / 127.0) * passbandWidth * 20000.0) / 20000.0;
// tempVar now contains value to the nearest 50Hz If CW mode, add/remove the cwPitch.
double pitch = 0.0;
if ((this->mode.mk == modeCW || this->mode.mk == modeCW_R) && this->passbandWidth > 0.0006)
{
pitch = (600.0 - cwPitch) / 1000000.0;
}
2024-02-10 12:11:10 +00:00
2025-01-14 13:35:14 +00:00
double newPBT = round((tempVar + pitch) * 200000.0) / 200000.0; // Nearest 5Hz.
2024-02-10 12:11:10 +00:00
2025-01-14 13:35:14 +00:00
if (newPBT != this->PBTInner) {
this->PBTInner = newPBT;
double pbFreq = ((double)(this->PBTInner) / this->passbandWidth) * 127.0;
qint16 newFreq = pbFreq + 128;
if (newFreq >= 0 && newFreq <= 255) {
configPbtInner->blockSignals(true);
configPbtInner->setValue(newFreq);
configPbtInner->blockSignals(false);
}
2024-02-10 12:11:10 +00:00
}
2023-09-25 13:55:27 +00:00
}
2023-07-16 09:08:28 +00:00
}
2023-09-25 13:55:27 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::setPBTOuter (uchar val) {
2025-01-14 13:35:14 +00:00
if (rigCaps->manufacturer == manufKenwood)
2024-02-10 12:11:10 +00:00
{
2025-01-18 12:29:34 +00:00
ushort width=0;
if (this->mode.mk == modeLSB || this->mode.mk == modeUSB)
{
if (val == 1)
width = 50;
else if (val > 1 && val < 22)
width = (val-1) * 100;
}
if (double(width)/1000000.0 != this->PBTOuter)
{
this->PBTOuter = double(width)/1000000.0;
configPbtOuter->blockSignals(true);
configPbtOuter->setValue(val);
configPbtOuter->blockSignals(false);
}
2025-01-14 13:35:14 +00:00
} else
{
qint16 shift = (qint16)(val - 128);
double tempVar = ceil((shift / 127.0) * this->passbandWidth * 20000.0) / 20000.0;
// tempVar now contains value to the nearest 50Hz If CW mode, add/remove the cwPitch.
double pitch = 0.0;
if ((this->mode.mk == modeCW || this->mode.mk == modeCW_R) && this->passbandWidth > 0.0006)
{
pitch = (600.0 - cwPitch) / 1000000.0;
}
2024-02-10 12:11:10 +00:00
2025-01-14 13:35:14 +00:00
double newPBT = round((tempVar + pitch) * 200000.0) / 200000.0; // Nearest 5Hz.
2024-02-10 12:11:10 +00:00
2025-01-14 13:35:14 +00:00
if (newPBT != this->PBTOuter) {
this->PBTOuter = newPBT;
double pbFreq = ((double)(this->PBTOuter) / this->passbandWidth) * 127.0;
qint16 newFreq = pbFreq + 128;
if (newFreq >= 0 && newFreq <= 255) {
configPbtOuter->blockSignals(true);
configPbtOuter->setValue(newFreq);
configPbtOuter->blockSignals(false);
}
2024-02-10 12:11:10 +00:00
}
2023-09-25 13:55:27 +00:00
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setIFShift(uchar val)
{
configIfShift->setEnabled(true);
if (val != this->ifShift)
{
configIfShift->blockSignals(true);
configIfShift->setValue(val);
configIfShift->blockSignals(false);
this->ifShift = val;
}
}
void receiverWidget::setFrequencyLocally(freqt f, uchar vfo) {
// This function is a duplicate of the regular setFrequency
// function, but without the locking mechanism.
// It is separate because we may wish to do additional things
// differently for locally-generated frequency changes.
if (vfo < numVFO)
{
freqDisplay[vfo]->blockSignals(true);
freqDisplay[vfo]->setFrequency(f.Hz);
freqDisplay[vfo]->blockSignals(false);
}
if (vfo==0) {
this->freq = f;
for (const auto &b: rigCaps->bands)
{
// Highest frequency band is always first!
if (f.Hz >= b.lowFreq && f.Hz <= b.highFreq)
{
// This frequency is contained within this band!
if (currentBand.band != b.band) {
currentBand = b;
emit bandChanged(this->receiver,b);
}
break;
}
}
} else if (vfo==1)
{
this->unselectedFreq=f;
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setFrequency(freqt f, uchar vfo)
2023-09-26 17:46:04 +00:00
{
2025-01-06 21:05:28 +00:00
//qInfo() << "receiver:" << receiver << "Setting Frequency vfo=" << vfo << "Freq:" << f.Hz;
if(!allowAcceptFreqData)
return;
2024-03-31 11:46:32 +00:00
if (vfo < numVFO)
{
freqDisplay[vfo]->blockSignals(true);
freqDisplay[vfo]->setFrequency(f.Hz);
freqDisplay[vfo]->blockSignals(false);
}
2025-01-01 13:40:58 +00:00
if (vfo==0) {
2025-01-01 13:40:58 +00:00
this->freq = f;
for (const auto &b: rigCaps->bands)
{
// Highest frequency band is always first!
2025-01-01 13:40:58 +00:00
if (f.Hz >= b.lowFreq && f.Hz <= b.highFreq)
{
// This frequency is contained within this band!
if (currentBand.band != b.band) {
currentBand = b;
emit bandChanged(this->receiver,b);
}
break;
}
}
2024-12-31 18:38:43 +00:00
} else if (vfo==1)
{
2025-01-01 13:40:58 +00:00
this->unselectedFreq=f;
}
2023-09-26 17:46:04 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::showBandIndicators(bool en)
{
for (auto &bi: bandIndicators)
{
bi.line->setVisible(en);
bi.text->setVisible(en);
}
if (!bandIndicators.empty())
{
bandIndicatorsVisible=en;
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setBandIndicators(bool show, QString region, std::vector<bandType>* bands)
2023-09-26 17:46:04 +00:00
{
2024-06-12 16:11:01 +00:00
this->currentRegion = region;
QMutableVectorIterator<bandIndicator> it(bandIndicators);
while (it.hasNext())
{
bandIndicator band = it.next();
spectrum->removeItem(band.line);
spectrum->removeItem(band.text);
it.remove();
}
2024-06-10 22:58:33 +00:00
// Step through the bands and add all indicators!
2024-06-12 16:11:01 +00:00
if (show) {
for (auto &band: *bands)
{
if (band.region == "" || band.region == region) {
// Add band line to current scope!
bandIndicator b;
b.line = new QCPItemLine(spectrum);
b.line->setHead(QCPLineEnding::esLineArrow);
b.line->setTail(QCPLineEnding::esLineArrow);
b.line->setVisible(false);
2024-06-12 16:11:01 +00:00
b.line->setPen(QPen(band.color));
b.line->start->setCoords(double(band.lowFreq/1000000.0), spectrum->yAxis->range().upper-5);
b.line->end->setCoords(double(band.highFreq/1000000.0), spectrum->yAxis->range().upper-5);
b.text = new QCPItemText(spectrum);
b.text->setVisible(false);
2024-06-12 16:11:01 +00:00
b.text->setAntialiased(true);
b.text->setColor(band.color);
b.text->setFont(QFont(font().family(), 8));
b.text->setPositionAlignment(Qt::AlignTop);
b.text->setText(band.name);
b.text->position->setCoords(double(band.lowFreq/1000000.0), spectrum->yAxis->range().upper-10);
bandIndicators.append(b);
}
}
2024-06-10 22:58:33 +00:00
}
2024-07-15 18:13:13 +00:00
bandIndicatorsVisible=false;
2024-06-12 16:11:01 +00:00
}
2024-06-10 22:58:33 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::displaySettings(int numDigits, qint64 minf, qint64 maxf, int minStep,FctlUnit unit, std::vector<bandType>* bands)
2024-06-12 16:11:01 +00:00
{
2025-02-04 21:30:56 +00:00
this->minFreqMhz = minf / 1000000.0;
this->maxFreqMhz = maxf / 1000000.0;
for (uchar i=0;i<numVFO;i++)
freqDisplay[i]->setup(numDigits, minf, maxf, minStep, unit, bands);
2023-09-26 17:46:04 +00:00
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setUnit(FctlUnit unit)
2023-09-26 17:46:04 +00:00
{
for (uchar i=0;i<numVFO;i++)
freqDisplay[i]->setUnit(unit);
2023-09-26 17:46:04 +00:00
}
2023-09-25 13:55:27 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::newFrequency(qint64 freq,uchar vfo)
2023-09-26 17:46:04 +00:00
{
freqt f;
f.Hz = freq;
f.MHzDouble = f.Hz / (double)1E6;
2025-02-09 16:46:18 +00:00
if (f.Hz > 0 && !freqLock)
2023-09-26 17:46:04 +00:00
{
2025-01-01 13:40:58 +00:00
emit sendTrack(f.Hz-this->freq.Hz);
vfoCommandType t = queue->getVfoCommand(vfo_t(vfo),receiver,true);
queue->addUnique(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(f),false,t.receiver));
setFrequencyLocally(f, vfo);
tempLockAcceptFreqData();
//qInfo() << "Setting new frequency for rx:" << receiver << "vfo:" << vfo << "freq:" << f.Hz << "using:" << funcString[t.freqFunc];
2023-09-26 17:46:04 +00:00
}
}
2023-09-27 11:28:43 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::setRef(int ref)
2023-09-27 11:28:43 +00:00
{
configRef->setValue(ref);
}
2025-01-06 23:10:11 +00:00
void receiverWidget::setRefLimits(int lower, int upper)
2023-09-27 11:28:43 +00:00
{
configRef->setRange(lower,upper);
}
2025-01-06 23:10:11 +00:00
void receiverWidget::detachScope(bool state)
{
if (state)
{
2024-01-27 22:13:47 +00:00
windowLabel = new QLabel();
detachButton->setText("Attach");
qInfo(logGui()) << "Detaching scope" << (receiver?"Sub":"Main");
this->parentWidget()->layout()->replaceWidget(this,windowLabel);
2024-06-08 22:06:34 +00:00
QTimer::singleShot(1, this, [&](){
if(originalParent) {
this->originalParent->resize(1,1);
}
});
this->parentWidget()->resize(1,1);
this->setParent(NULL);
this-> setWindowFlags(Qt::Window | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);
this->move(screen()->geometry().center() - frameGeometry().center());
} else {
detachButton->setText("Detach");
qInfo(logGui()) << "Attaching scope" << (receiver?"Sub":"Main");
windowLabel->parentWidget()->layout()->replaceWidget(windowLabel,this);
2024-06-08 22:06:34 +00:00
QTimer::singleShot(1, this, [&](){
if(originalParent) {
this->originalParent->resize(1,1);
}
});
windowLabel->setParent(NULL);
delete windowLabel;
}
2024-01-27 22:13:47 +00:00
// Force a redraw?
this->show();
}
2024-07-13 18:19:27 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::changeSpan(qint8 val)
2024-07-13 18:19:27 +00:00
{
if ((val > 0 && spanCombo->currentIndex() < spanCombo->count()-val) ||
2024-08-13 11:47:31 +00:00
(val < char(0) && spanCombo->currentIndex() > 0))
2024-07-13 18:19:27 +00:00
{
spanCombo->setCurrentIndex(spanCombo->currentIndex() + val);
}
else
{
2024-08-13 11:47:31 +00:00
if (val < char(0))
2024-07-13 18:19:27 +00:00
spanCombo->setCurrentIndex(spanCombo->count()-1);
else
spanCombo->setCurrentIndex(0);
}
}
2025-01-06 23:10:11 +00:00
void receiverWidget::updateBSR(std::vector<bandType>* bands)
{
// Send a new BSR value for the current frequency.
2024-12-27 13:26:26 +00:00
// Not currently used.
for (auto &b: *bands)
{
2024-08-13 07:38:55 +00:00
if (quint64(freqDisplay[0]->getFrequency()) >= b.lowFreq && quint64(freqDisplay[0]->getFrequency()) <= b.highFreq)
{
if(b.bsr != 0)
{
bandStackType bs(b.bsr,1);
bs.data=dataCombo->currentIndex();
bs.filter=filterCombo->currentData().toInt();
bs.freq.Hz = freqDisplay[0]->getFrequency();
bs.freq.MHzDouble=bs.freq.Hz/1000000.0;
bs.mode=scopeModeCombo->currentData().toInt();
2024-07-26 22:50:34 +00:00
bs.sql=0;
2024-12-27 13:26:26 +00:00
bs.tone.tone=770;
bs.tsql.tone=770;
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->addUnique(priorityImmediate,queueItem(funcBandStackReg,QVariant::fromValue<bandStackType>(bs),false,t.receiver));
}
break;
}
}
}
2024-11-18 09:03:14 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::memoryMode(bool en)
2024-11-18 09:03:14 +00:00
{
this->memMode=en;
qInfo(logRig) << "Receiver" << receiver << "Memory mode:" << en;
if (en) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,false);
queue->del(t.freqFunc,t.receiver);
queue->del(t.modeFunc,t.receiver);
2024-11-18 09:03:14 +00:00
}
}
2025-01-06 23:10:11 +00:00
QImage receiverWidget::getSpectrumImage()
{
QMutexLocker locker(&mutex);
return spectrum->toPixmap().toImage();
}
2025-01-06 23:10:11 +00:00
QImage receiverWidget::getWaterfallImage()
{
QMutexLocker locker(&mutex);
return waterfall->toPixmap().toImage();
}
2024-12-31 18:38:43 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::vfoSwap()
2024-12-31 18:38:43 +00:00
{
2025-01-01 13:40:58 +00:00
if (!tracking) {
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
2025-01-01 13:40:58 +00:00
if (rigCaps->commands.contains(funcVFOSwapAB))
{
queue->add(priorityImmediate,funcVFOSwapAB,false,t.receiver);
2025-01-01 13:40:58 +00:00
}
else
{
// Manufacture a VFO Swap (should be fun!)
queue->add(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(unselectedFreq),false,t.receiver));
queue->add(priorityImmediate,queueItem(t.modeFunc,QVariant::fromValue<modeInfo>(unselectedMode),false,t.receiver));
t = queue->getVfoCommand(vfoB,receiver,true);
queue->add(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(freq),false,t.receiver));
queue->add(priorityImmediate,queueItem(t.modeFunc,QVariant::fromValue<modeInfo>(mode),false,t.receiver));
2025-01-01 13:40:58 +00:00
}
2024-12-31 18:38:43 +00:00
}
2025-01-01 13:40:58 +00:00
}
2024-12-31 18:38:43 +00:00
2025-01-06 23:10:11 +00:00
void receiverWidget::receiveTrack(int f)
2025-01-01 13:40:58 +00:00
{
return; // Disabled for now.
2025-01-01 13:40:58 +00:00
qInfo(logRig) << "Got tracking for rx" << receiver<< "amount" << f << "Hz";
if (tracking && receiver) {
// OK I am the sub receiver so lets try this.
freqt freqGo;
freqGo.Hz=this->freq.Hz+f;
freqGo.MHzDouble = (float)freqGo.Hz / 1E6;
freqGo.VFO = activeVFO;
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,true);
queue->add(priorityImmediate,queueItem(t.freqFunc,QVariant::fromValue<freqt>(freqGo),false,t.receiver));
2025-01-01 13:40:58 +00:00
freq=freqGo;
}
2024-12-31 18:38:43 +00:00
}
2025-01-23 10:39:35 +00:00
// This function will request an update of all freq/mode info from the rig
void receiverWidget::updateInfo()
{
// If we are not the active receiver, delete selected/unselected commands
vfoCommandType t = queue->getVfoCommand(vfoA,receiver,false);
queue->add(priorityImmediate,t.freqFunc,false,t.receiver);
queue->add(priorityImmediate,t.modeFunc,false,t.receiver);
if ((rigCaps->hasCommand29 || !receiver) && numVFO > 1) {
t = queue->getVfoCommand(vfoB,receiver,false);
queue->add(priorityImmediate,t.freqFunc,false,t.receiver);
queue->add(priorityImmediate,t.modeFunc,false,t.receiver);
}
}