From 2266e8dbb748a2ca849206a6d3144c8c5d377268 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 16 Sep 2020 17:02:40 -0400 Subject: [PATCH 01/16] Add FLow and FHigh spinner controls to set the FST4 decoding range. --- displayWidgets.txt | 44 +-- widgets/mainwindow.cpp | 98 ++++-- widgets/mainwindow.h | 4 +- widgets/mainwindow.ui | 737 ++++++++++++++++++++++------------------- widgets/plotter.cpp | 20 +- widgets/plotter.h | 5 + widgets/widegraph.cpp | 5 + widgets/widegraph.h | 1 + 8 files changed, 510 insertions(+), 404 deletions(-) diff --git a/displayWidgets.txt b/displayWidgets.txt index 9b438590c..a3f31eef2 100644 --- a/displayWidgets.txt +++ b/displayWidgets.txt @@ -1,27 +1,27 @@ Here are the "displayWidgets()" strings for WSJT-X modes 1 2 3 - 0123456789012345678901234567890123 ----------------------------------------------- -JT4 1110100000001100001100000000000000 -JT4/VHF 1111100100101101101111000000000000 -JT9 1110100000001110000100000000000010 -JT9/VHF 1111101010001111100100000000000000 -JT9+JT65 1110100000011110000100000000000010 -JT65 1110100000001110000100000000000010 -JT65/VHF 1111100100001101101011000100000000 -QRA64 1111100101101101100000000010000000 -ISCAT 1001110000000001100000000000000000 -MSK144 1011111101000000000100010000000000 -WSPR 0000000000000000010100000000000000 -FST4 1111110001001110000100000001000000 -FST4W 0000000000000000010100000000000001 -Echo 0000000000000000000000100000000000 -FCal 0011010000000000000000000000010000 -FT8 1110100001001110000100001001100010 -FT8/VHF 1110100001001110000100001001100010 -FT8/Fox 1110100001001110000100000000001000 -FT8/Hound 1110100001001110000100000000001100 + 012345678901234567890123456789012345 +------------------------------------------------ +JT4 111010000000110000110000000000000000 +JT4/VHF 111110010010110110111100000000000000 +JT9 111010000000111000010000000000001000 +JT9/VHF 111110101000111110010000000000000000 +JT9+JT65 111010000001111000010000000000001000 +JT65 111010000000111000010000000000001000 +JT65/VHF 111110010000110110101100010000000000 +QRA64 111110010110110110000000001000000000 +ISCAT 100111000000000110000000000000000000 +MSK144 101111110100000000010001000000000000 +WSPR 000000000000000001010000000000000000 +FST4 111111000100111000010000000100000011 +FST4W 000000000000000001010000000000000100 +Echo 000000000000000000000010000000000000 +FCal 001101000000000000000000000001000000 +FT8 111010000100111000010000100110001000 +FT8/VHF 111010000100111000010000100110001000 +FT8/Fox 111010000100111000010000000000100000 +FT8/Hound 111010000100111000010000000000110000 ---------------------------------------------- 1 2 3 012345678901234567890123456789012 @@ -63,3 +63,5 @@ Mapping of column numbers to widgets 31. cbRxAll 32. cbCQonly 33. sbTR_FST4W +34. sbF_Low +35. sbF_High diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 3e046173c..6ff5351c2 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -208,7 +208,7 @@ namespace // grid exact match excluding RR73 QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"}; auto quint32_max = std::numeric_limits::max (); - constexpr int N_WIDGETS {34}; + constexpr int N_WIDGETS {36}; constexpr int rx_chunk_size {3456}; // audio samples at 12000 Hz constexpr int tx_audio_buffer_size {48000 / 5}; // audio frames at 48000 Hz @@ -1135,6 +1135,8 @@ void MainWindow::writeSettings() m_settings->setValue("WSPRfreq",ui->WSPRfreqSpinBox->value()); m_settings->setValue("FST4W_RxFreq",ui->sbFST4W_RxFreq->value()); m_settings->setValue("FST4W_FTol",ui->sbFST4W_FTol->value()); + m_settings->setValue("FST4_FLow",ui->sbF_Low->value()); + m_settings->setValue("FST4_FHigh",ui->sbF_High->value()); m_settings->setValue("SubMode",ui->sbSubmode->value()); m_settings->setValue("DTtol",m_DTtol); m_settings->setValue("Ftol", ui->sbFtol->value ()); @@ -1222,6 +1224,8 @@ void MainWindow::readSettings() ui->RxFreqSpinBox->setValue(m_settings->value("RxFreq",1500).toInt()); ui->sbFST4W_RxFreq->setValue(0); ui->sbFST4W_RxFreq->setValue(m_settings->value("FST4W_RxFreq",1500).toInt()); + ui->sbF_Low->setValue(m_settings->value("FST4_FLow",600).toInt()); + ui->sbF_High->setValue(m_settings->value("FST4_FHigh",1400).toInt()); m_nSubMode=m_settings->value("SubMode",0).toInt(); ui->sbFtol->setValue (m_settings->value("Ftol", 50).toInt()); ui->sbFST4W_FTol->setValue(m_settings->value("FST4W_FTol",100).toInt()); @@ -1427,6 +1431,10 @@ void MainWindow::dataSink(qint64 frames) // Get power, spectrum, and ihsym dec_data.params.nfa=m_wideGraph->nStartFreq(); dec_data.params.nfb=m_wideGraph->Fmax(); + if(m_mode=="FST4") { + dec_data.params.nfa=ui->sbF_Low->value(); + dec_data.params.nfb=ui->sbF_High->value(); + } int nsps=m_nsps; if(m_bFastMode) nsps=6912; int nsmo=m_wideGraph->smoothYellow()-1; @@ -4224,7 +4232,7 @@ void MainWindow::guiUpdate() //Once per second (onesec) if(nsec != m_sec0) { // qDebug() << "AAA" << nsec; - if(m_mode=="FST4") sbFtolMaxVal(); + if(m_mode=="FST4") chk_FST4_freq_range(); m_currentBand=m_config.bands()->find(m_freqNominal); if( SpecOp::HOUND == m_config.special_op_id() ) { qint32 tHound=QDateTime::currentMSecsSinceEpoch()/1000 - m_tAutoOn; @@ -5870,6 +5878,8 @@ void MainWindow::displayWidgets(qint64 n) if(i==31) ui->cbRxAll->setVisible(b); if(i==32) ui->cbCQonly->setVisible(b); if(i==33) ui->sbTR_FST4W->setVisible(b); + if(i==34) ui->sbF_Low->setVisible(b); + if(i==35) ui->sbF_High->setVisible(b); j=j>>1; } ui->pbBestSP->setVisible(m_mode=="FT4"); @@ -5902,12 +5912,12 @@ void MainWindow::on_actionFST4_triggered() ui->label_6->setText(tr ("Band Activity")); ui->label_7->setText(tr ("Rx Frequency")); WSPR_config(false); -// 0123456789012345678901234567890123 - displayWidgets(nWidgets("1111110001001110000100000001000000")); +// 012345678901234567890123456789012345 + displayWidgets(nWidgets("111111000100111000010000000100000011")); setup_status_bar(false); ui->sbTR->values ({15, 30, 60, 120, 300, 900, 1800}); on_sbTR_valueChanged (ui->sbTR->value()); - sbFtolMaxVal(); + chk_FST4_freq_range(); ui->cbAutoSeq->setChecked(true); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); @@ -5915,6 +5925,7 @@ void MainWindow::on_actionFST4_triggered() m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); m_wideGraph->setTol(ui->sbFtol->value()); m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); + m_wideGraph->setFST4_FreqRange(ui->sbF_Low->value(),ui->sbF_High->value()); switch_mode (Modes::FST4); m_wideGraph->setMode(m_mode); statusChanged(); @@ -5933,8 +5944,8 @@ void MainWindow::on_actionFST4W_triggered() m_FFTSize = m_nsps / 2; Q_EMIT FFTSize(m_FFTSize); WSPR_config(true); -// 0123456789012345678901234567890123 - displayWidgets(nWidgets("0000000000000000010100000000000001")); +// 012345678901234567890123456789012345 + displayWidgets(nWidgets("000000000000000001010000000000000100")); setup_status_bar(false); ui->band_hopping_group_box->setChecked(false); ui->band_hopping_group_box->setVisible(false); @@ -5982,7 +5993,7 @@ void MainWindow::on_actionFT4_triggered() ui->label_7->setText(tr ("Rx Frequency")); ui->label_6->setText(tr ("Band Activity")); ui->decodedTextLabel->setText( " UTC dB DT Freq " + tr ("Message")); - displayWidgets(nWidgets("1110100001001110000100000001100010")); + displayWidgets(nWidgets("111010000100111000010000000110001000")); ui->txrb2->setEnabled(true); ui->txrb4->setEnabled(true); ui->txrb5->setEnabled(true); @@ -6031,7 +6042,7 @@ void MainWindow::on_actionFT8_triggered() ui->label_6->setText(tr ("Band Activity")); ui->decodedTextLabel->setText( " UTC dB DT Freq " + tr ("Message")); } - displayWidgets(nWidgets("1110100001001110000100001001100010")); + displayWidgets(nWidgets("111010000100111000010000100110001000")); ui->txrb2->setEnabled(true); ui->txrb4->setEnabled(true); ui->txrb5->setEnabled(true); @@ -6049,7 +6060,7 @@ void MainWindow::on_actionFT8_triggered() ui->cbAutoSeq->setEnabled(false); ui->tabWidget->setCurrentIndex(1); ui->TxFreqSpinBox->setValue(300); - displayWidgets(nWidgets("1110100001001110000100000000001000")); + displayWidgets(nWidgets("111010000100111000010000000000100000")); ui->labDXped->setText(tr ("Fox")); on_fox_log_action_triggered(); } @@ -6059,7 +6070,7 @@ void MainWindow::on_actionFT8_triggered() ui->cbAutoSeq->setEnabled(false); ui->tabWidget->setCurrentIndex(0); ui->cbHoldTxFreq->setChecked(true); - displayWidgets(nWidgets("1110100001001100000100000000001100")); + displayWidgets(nWidgets("111010000100110000010000000000110000")); ui->labDXped->setText(tr ("Hound")); ui->txrb1->setChecked(true); ui->txrb2->setEnabled(false); @@ -6134,9 +6145,9 @@ void MainWindow::on_actionJT4_triggered() ui->sbSubmode->setValue(0); } if(bVHF) { - displayWidgets(nWidgets("1111100100101101101111000000000000")); + displayWidgets(nWidgets("111110010010110110111100000000000000")); } else { - displayWidgets(nWidgets("1110100000001100001100000000000000")); + displayWidgets(nWidgets("111010000000110000110000000000000000")); } fast_config(false); statusChanged(); @@ -6193,9 +6204,9 @@ void MainWindow::on_actionJT9_triggered() ui->label_6->setText(tr ("Band Activity")); ui->label_7->setText(tr ("Rx Frequency")); if(bVHF) { - displayWidgets(nWidgets("1111101010001111100100000000000000")); + displayWidgets(nWidgets("111110101000111110010000000000000000")); } else { - displayWidgets(nWidgets("1110100000001110000100000000000010")); + displayWidgets(nWidgets("111010000000111000010000000000001000")); } fast_config(m_bFastMode); ui->cbAutoSeq->setVisible(m_bFast9); @@ -6234,7 +6245,7 @@ void MainWindow::on_actionJT9_JT65_triggered() ui->label_7->setText(tr ("Rx Frequency")); ui->decodedTextLabel->setText("UTC dB DT Freq " + tr ("Message")); ui->decodedTextLabel2->setText("UTC dB DT Freq " + tr ("Message")); - displayWidgets(nWidgets("1110100000011110000100000000000010")); + displayWidgets(nWidgets("111010000001111000010000000000001000")); fast_config(false); statusChanged(); } @@ -6282,9 +6293,9 @@ void MainWindow::on_actionJT65_triggered() ui->label_7->setText(tr ("Rx Frequency")); } if(bVHF) { - displayWidgets(nWidgets("1111100100001101101011000100000000")); + displayWidgets(nWidgets("111110010000110110101100010000000000")); } else { - displayWidgets(nWidgets("1110100000001110000100000000000010")); + displayWidgets(nWidgets("111010000000111000010000000000001000")); } fast_config(false); if(ui->cbShMsgs->isChecked()) { @@ -6316,7 +6327,7 @@ void MainWindow::on_actionQRA64_triggered() ui->TxFreqSpinBox->setValue(1000); QString fname {QDir::toNativeSeparators(m_config.temp_dir ().absoluteFilePath ("red.dat"))}; m_wideGraph->setRedFile(fname); - displayWidgets(nWidgets("1111100100101101100000000010000000")); + displayWidgets(nWidgets("111110010010110110000000001000000000")); statusChanged(); } @@ -6353,7 +6364,7 @@ void MainWindow::on_actionISCAT_triggered() ui->sbSubmode->setMaximum(1); if(m_nSubMode==0) ui->TxFreqSpinBox->setValue(1012); if(m_nSubMode==1) ui->TxFreqSpinBox->setValue(560); - displayWidgets(nWidgets("1001110000000001100000000000000000")); + displayWidgets(nWidgets("100111000000000110000000000000000000")); fast_config(true); statusChanged (); } @@ -6415,7 +6426,7 @@ void MainWindow::on_actionMSK144_triggered() ui->rptSpinBox->setValue(0); ui->rptSpinBox->setSingleStep(1); ui->sbFtol->values ({20, 50, 100, 200}); - displayWidgets(nWidgets("1011111101000000000100010000100000")); + displayWidgets(nWidgets("101111110100000000010001000010000000")); fast_config(m_bFastMode); statusChanged(); @@ -6455,7 +6466,7 @@ void MainWindow::on_actionWSPR_triggered() m_bFastMode=false; m_bFast9=false; ui->TxFreqSpinBox->setValue(ui->WSPRfreqSpinBox->value()); - displayWidgets(nWidgets("0000000000000000010100000000000000")); + displayWidgets(nWidgets("000000000000000001010000000000000000")); fast_config(false); statusChanged(); } @@ -6488,7 +6499,7 @@ void MainWindow::on_actionEcho_triggered() m_bFast9=false; WSPR_config(true); ui->decodedTextLabel->setText(" UTC N Level Sig DF Width Q"); - displayWidgets(nWidgets("0000000000000000000000100000000000")); + displayWidgets(nWidgets("000000000000000000000010000000000000")); fast_config(false); statusChanged(); } @@ -6514,7 +6525,7 @@ void MainWindow::on_actionFreqCal_triggered() // 18:15:47 0 1 1500 1550.349 0.100 3.5 10.2 ui->decodedTextLabel->setText(" UTC Freq CAL Offset fMeas DF Level S/N"); ui->measure_check_box->setChecked (false); - displayWidgets(nWidgets("0011010000000000000000000000010000")); + displayWidgets(nWidgets("001101000000000000000000000001000000")); statusChanged(); } @@ -6620,6 +6631,35 @@ void MainWindow::on_RxFreqSpinBox_valueChanged(int n) statusUpdate (); } +void MainWindow::on_sbF_Low_valueChanged(int n) +{ + m_wideGraph->setFST4_FreqRange(n,ui->sbF_High->value()); + chk_FST4_freq_range(); +} + +void MainWindow::on_sbF_High_valueChanged(int n) +{ + m_wideGraph->setFST4_FreqRange(ui->sbF_Low->value(),n); + chk_FST4_freq_range(); +} + +void MainWindow::chk_FST4_freq_range() +{ + int maxDiff=2000; + if(m_TRperiod==120) maxDiff=1000; + if(m_TRperiod==300) maxDiff=400; + if(m_TRperiod>=900) maxDiff=200; + int diff=ui->sbF_High->value() - ui->sbF_Low->value(); + + if(diff<100 or diff>maxDiff) { + ui->sbF_Low->setStyleSheet("QSpinBox { background-color: red; }"); + ui->sbF_High->setStyleSheet("QSpinBox { background-color: red; }"); + } else { + ui->sbF_Low->setStyleSheet(""); + ui->sbF_High->setStyleSheet(""); + } +} + void MainWindow::on_actionQuickDecode_toggled (bool checked) { m_ndepth ^= (-checked ^ m_ndepth) & 0x00000001; @@ -7467,7 +7507,7 @@ void MainWindow::on_sbTR_valueChanged(int value) m_wideGraph->setPeriod (value, m_nsps); progressBar.setMaximum (value); } - if(m_mode=="FST4") sbFtolMaxVal(); + if(m_mode=="FST4") chk_FST4_freq_range(); if(m_monitoring) { on_stopButton_clicked(); on_monitorButton_clicked(true); @@ -7478,14 +7518,6 @@ void MainWindow::on_sbTR_valueChanged(int value) statusUpdate (); } -void MainWindow::sbFtolMaxVal() -{ - if(m_TRperiod<=60) ui->sbFtol->setMaximum(1000); - if(m_TRperiod==120) ui->sbFtol->setMaximum(500); - if(m_TRperiod==300) ui->sbFtol->setMaximum(200); - if(m_TRperiod>=900) ui->sbFtol->setMaximum(100); -} - void MainWindow::on_sbTR_FST4W_valueChanged(int value) { on_sbTR_valueChanged(value); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 042866fe2..264e0cac5 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -305,6 +305,9 @@ private slots: void on_sbNlist_valueChanged(int n); void on_sbNslots_valueChanged(int n); void on_sbMax_dB_valueChanged(int n); + void on_sbF_Low_valueChanged(int n); + void on_sbF_High_valueChanged(int n); + void chk_FST4_freq_range(); void on_pbFoxReset_clicked(); void on_comboBoxHoundSort_activated (int index); void not_GA_warning_message (); @@ -312,7 +315,6 @@ private slots: void on_pbBestSP_clicked(); void on_RoundRobin_currentTextChanged(QString text); void setTxMsg(int n); - void sbFtolMaxVal(); bool stdCall(QString const& w); void remote_configure (QString const& mode, quint32 frequency_tolerance, QString const& submode , bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 5ade13659..9779fe3bb 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -658,6 +658,299 @@ QPushButton[state="ok"] { + + + + + + <html><head/><body><p>Check to use short-format messages.</p></body></html> + + + Check to use short-format messages. + + + Sh + + + + + + + <html><head/><body><p>Check to enable JT9 fast modes</p></body></html> + + + Check to enable JT9 fast modes + + + Fast + + + + + + + <html><head/><body><p>Check to enable automatic sequencing of Tx messages based on received messages.</p></body></html> + + + Check to enable automatic sequencing of Tx messages based on received messages. + + + Auto Seq + + + + + + + <html><head/><body><p>Check to call the first decoded responder to my CQ.</p></body></html> + + + Check to call the first decoded responder to my CQ. + + + Call 1st + + + + + + + false + + + Check to generate "@1250 (SEND MSGS)" in Tx6. + + + Tx6 + + + + + + + + + <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> + + + Submode determines tone spacing; A is narrowest. + + + Qt::AlignCenter + + + Submode + + + 0 + + + 7 + + + + + + + + + false + + + <html><head/><body><p>Frequency to call CQ on in kHz above the current MHz</p></body></html> + + + Frequency to call CQ on in kHz above the current MHz + + + Tx CQ + + + 1 + + + 999 + + + 260 + + + + + + + false + + + <html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html> + + + Check this to call CQ on the "Tx CQ" frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on. +Not available to nonstandard callsign holders. + + + + + + + + + + Rx All Freqs + + + + + + + + + true + + + + 0 + 0 + + + + Toggle Tx mode + + + Tx JT9 @ + + + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + Fox + + + Qt::AlignCenter + + + + + + + <html><head/><body><p>Check to monitor Sh messages.</p></body></html> + + + Check to monitor Sh messages. + + + SWL + + + + + + + QPushButton:checked { + color: rgb(0, 0, 0); + background-color: red; + border-style: outset; + border-width: 1px; + border-radius: 5px; + border-color: black; + min-width: 5em; + padding: 3px; +} + + + Best S+P + + + true + + + + + + + <html><head/><body><p>Check this to start recording calibration data.<br/>While measuring calibration correction is disabled.<br/>When not checked you can view the calibration results.</p></body></html> + + + Check this to start recording calibration data. +While measuring calibration correction is disabled. +When not checked you can view the calibration results. + + + Measure + + + + + + + + + Audio Tx frequency + + + Qt::AlignCenter + + + Hz + + + Tx + + + 200 + + + 5000 + + + 1500 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Tx# + + + 1 + + + 4095 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -671,32 +964,108 @@ QPushButton[state="ok"] { - - + + - Audio Rx frequency + <html><head/><body><p>Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences.</p></body></html> + + + Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences. + + + Tx even/1st + + + + + + + <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> + + + Synchronizing threshold. Lower numbers accept weaker sync signals. Qt::AlignCenter - - Hz - - Rx + Sync - 200 + -1 + + + 10 + + + 1 + + + + + + + <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> + + + Double-click on another caller to queue that call for your next QSO. + + + Next Call + + + Qt::AlignCenter + + + + + + + Qt::AlignCenter + + + F Low + + + 100 5000 + + 100 + - 1500 + 600 - + + + + Qt::AlignCenter + + + + + + F High + + + 100 + + + 5000 + + + 100 + + + 1400 + + + + @@ -784,265 +1153,32 @@ QPushButton[state="ok"] { - - + + - <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> - - - Synchronizing threshold. Lower numbers accept weaker sync signals. + Audio Rx frequency Qt::AlignCenter + + Hz + - Sync + Rx - -1 + 200 - 10 + 5000 - 1 + 1500 - - - - - - <html><head/><body><p>Check to use short-format messages.</p></body></html> - - - Check to use short-format messages. - - - Sh - - - - - - - <html><head/><body><p>Check to enable JT9 fast modes</p></body></html> - - - Check to enable JT9 fast modes - - - Fast - - - - - - - <html><head/><body><p>Check to enable automatic sequencing of Tx messages based on received messages.</p></body></html> - - - Check to enable automatic sequencing of Tx messages based on received messages. - - - Auto Seq - - - - - - - <html><head/><body><p>Check to call the first decoded responder to my CQ.</p></body></html> - - - Check to call the first decoded responder to my CQ. - - - Call 1st - - - - - - - false - - - Check to generate "@1250 (SEND MSGS)" in Tx6. - - - Tx6 - - - - - - - - - <html><head/><body><p>Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences.</p></body></html> - - - Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences. - - - Tx even/1st - - - - - - - - - false - - - <html><head/><body><p>Frequency to call CQ on in kHz above the current MHz</p></body></html> - - - Frequency to call CQ on in kHz above the current MHz - - - Tx CQ - - - 1 - - - 999 - - - 260 - - - - - - - false - - - <html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html> - - - Check this to call CQ on the "Tx CQ" frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on. -Not available to nonstandard callsign holders. - - - - - - - - - - Rx All Freqs - - - - - - - - - <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> - - - Submode determines tone spacing; A is narrowest. - - - Qt::AlignCenter - - - Submode - - - 0 - - - 7 - - - - - - - - - - 0 - 0 - - - - - 100 - 16777215 - - - - Fox - - - Qt::AlignCenter - - - - - - - <html><head/><body><p>Check to monitor Sh messages.</p></body></html> - - - Check to monitor Sh messages. - - - SWL - - - - - - - QPushButton:checked { - color: rgb(0, 0, 0); - background-color: red; - border-style: outset; - border-width: 1px; - border-radius: 5px; - border-color: black; - min-width: 5em; - padding: 3px; -} - - - Best S+P - - - true - - - - - - - <html><head/><body><p>Check this to start recording calibration data.<br/>While measuring calibration correction is disabled.<br/>When not checked you can view the calibration results.</p></body></html> - - - Check this to start recording calibration data. -While measuring calibration correction is disabled. -When not checked you can view the calibration results. - - - Measure - - - - - - + <html><head/><body><p>Signal report: Signal-to-noise ratio in 2500 Hz reference bandwidth (dB).</p></body></html> @@ -1067,7 +1203,7 @@ When not checked you can view the calibration results. - + <html><head/><body><p>Tx/Rx or Frequency calibration sequence length</p></body></html> @@ -1095,95 +1231,6 @@ When not checked you can view the calibration results. - - - - true - - - - 0 - 0 - - - - Toggle Tx mode - - - Tx JT9 @ - - - - - - - Audio Tx frequency - - - Qt::AlignCenter - - - Hz - - - Tx - - - 200 - - - 5000 - - - 1500 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - Tx# - - - 1 - - - 4095 - - - - - - - <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> - - - Double-click on another caller to queue that call for your next QSO. - - - Next Call - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -3348,8 +3395,6 @@ Yellow when too low addButton txFirstCheckBox TxFreqSpinBox - rptSpinBox - sbTR sbCQTxFreq cbCQTx cbShMsgs diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index 9fdf66cef..bc7b2270d 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -506,11 +506,20 @@ void CPlotter::DrawOverlay() //DrawOverlay() or m_mode=="QRA64" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { + if(m_mode=="FST4") { + x1=XfromFreq(m_nfa); + x2=XfromFreq(m_nfb); + painter0.drawLine(x1,25,x1+5,30); // Mark FST4 F_Low + painter0.drawLine(x1,25,x1+5,20); + painter0.drawLine(x2,25,x2-5,30); // Mark FST4 F_High + painter0.drawLine(x2,25,x2-5,20); + } + if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) { painter0.setPen(penGreen); x1=XfromFreq(m_rxFreq-m_tol); x2=XfromFreq(m_rxFreq+m_tol); - painter0.drawLine(x1,28,x2,28); + painter0.drawLine(x1,26,x2,26); x1=XfromFreq(m_rxFreq); painter0.drawLine(x1,24,x1,30); @@ -539,8 +548,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() x1=XfromFreq(m_rxFreq-m_tol); x2=XfromFreq(m_rxFreq+m_tol); painter0.drawLine(x1,26,x2,26); // Mark the Tol range - } - } + } } } if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or @@ -809,6 +817,12 @@ void CPlotter::setFlatten(bool b1, bool b2) void CPlotter::setTol(int n) //setTol() { m_tol=n; +} + +void CPlotter::setFST4_FreqRange(int fLow,int fHigh) +{ + m_nfa=fLow; + m_nfb=fHigh; DrawOverlay(); } diff --git a/widgets/plotter.h b/widgets/plotter.h index b4b4cf42b..3787fafe0 100644 --- a/widgets/plotter.h +++ b/widgets/plotter.h @@ -83,6 +83,9 @@ public: void drawRed(int ia, int ib, float swide[]); void setVHF(bool bVHF); void setRedFile(QString fRed); + void setFST4_FreqRange(int fLow,int fHigh); + + bool scaleOK () const {return m_bScaleOK;} signals: void freezeDecode1(int n); @@ -125,6 +128,8 @@ private: qint32 m_nSubMode; qint32 m_ia; qint32 m_ib; + qint32 m_nfa; + qint32 m_nfb; QPixmap m_WaterfallPixmap; QPixmap m_2DPixmap; diff --git a/widgets/widegraph.cpp b/widgets/widegraph.cpp index c29d84989..389986c84 100644 --- a/widgets/widegraph.cpp +++ b/widgets/widegraph.cpp @@ -500,6 +500,11 @@ void WideGraph::setTol(int n) //setTol ui->widePlot->update(); } +void WideGraph::setFST4_FreqRange(int fLow,int fHigh) +{ + ui->widePlot->setFST4_FreqRange(fLow,fHigh); +} + void WideGraph::on_smoSpinBox_valueChanged(int n) { m_nsmo=n; diff --git a/widgets/widegraph.h b/widgets/widegraph.h index 90f7b51aa..d26328fdb 100644 --- a/widgets/widegraph.h +++ b/widgets/widegraph.h @@ -49,6 +49,7 @@ public: void drawRed(int ia, int ib); void setVHF(bool bVHF); void setRedFile(QString fRed); + void setFST4_FreqRange(int fLow,int fHigh); signals: void freezeDecode2(int n); From 21dc6a5c596be9a1ca1c3edd96894b618c8d30da Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 16 Sep 2020 17:23:59 -0400 Subject: [PATCH 02/16] Connect the FLow and FHigh limits for FST4 decoding. --- lib/fst4_decode.f90 | 11 ++++++++--- widgets/mainwindow.cpp | 6 +++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 5d953e0e4..a4cce0dcd 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -64,7 +64,7 @@ contains integer naptypes(0:5,4) ! (nQSOProgress,decoding pass) integer mcq(29),mrrr(19),m73(19),mrr73(19) - logical badsync,unpk77_success + logical badsync,unpk77_success,single_decode logical first,nohiscall,lwspr,ex integer*2 iwave(30*60*12000) @@ -232,8 +232,13 @@ contains nhicoh=1 nsyncoh=8 - fa=max(100,nint(nfqso+1.5*baud-ntol)) - fb=min(4800,nint(nfqso+1.5*baud+ntol)) + fa=nfa + fb=nfb + single_decode=iand(nexp_decode,32).ne.0 + if(single_decode) then + fa=max(100,nint(nfqso+1.5*baud-ntol)) + fb=min(4800,nint(nfqso+1.5*baud+ntol)) + endif minsync=1.20 if(ntrperiod.eq.15) minsync=1.15 diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 6ff5351c2..99d42cb6a 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3075,7 +3075,11 @@ void MainWindow::decode() //decode() dec_data.params.ntol=20; dec_data.params.naggressive=0; } - if(m_mode=="FST4") dec_data.params.ntol=ui->sbFtol->value(); + if(m_mode=="FST4") { + dec_data.params.ntol=ui->sbFtol->value(); + dec_data.params.nfa=ui->sbF_Low->value(); + dec_data.params.nfb=ui->sbF_High->value(); + } if(m_mode=="FST4W") dec_data.params.ntol=ui->sbFST4W_FTol->value(); if(dec_data.params.nutc < m_nutc0) m_RxLog = 1; //Date and Time to file "ALL.TXT". if(dec_data.params.newdat==1 and !m_diskData) m_nutc0=dec_data.params.nutc; From e60fc1ca196914d4bf0431abe1ae940eefb237ba Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 16 Sep 2020 20:16:32 -0400 Subject: [PATCH 03/16] FST4 GUI controls for FLow, FHigh, should disappear when Single Decode is checked. And some related improvements. --- widgets/mainwindow.cpp | 26 ++++++++++++++++++++++---- widgets/plotter.cpp | 13 +++++++++++-- widgets/plotter.h | 3 ++- widgets/widegraph.cpp | 5 +++++ widgets/widegraph.h | 1 + 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 99d42cb6a..7d81f6868 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3077,8 +3077,13 @@ void MainWindow::decode() //decode() } if(m_mode=="FST4") { dec_data.params.ntol=ui->sbFtol->value(); - dec_data.params.nfa=ui->sbF_Low->value(); - dec_data.params.nfb=ui->sbF_High->value(); + if(m_config.single_decode()) { + dec_data.params.nfa=m_wideGraph->rxFreq() - ui->sbFtol->value(); + dec_data.params.nfb=m_wideGraph->rxFreq() + ui->sbFtol->value(); + } else { + dec_data.params.nfa=ui->sbF_Low->value(); + dec_data.params.nfb=ui->sbF_High->value(); + } } if(m_mode=="FST4W") dec_data.params.ntol=ui->sbFST4W_FTol->value(); if(dec_data.params.nutc < m_nutc0) m_RxLog = 1; //Date and Time to file "ALL.TXT". @@ -5916,8 +5921,14 @@ void MainWindow::on_actionFST4_triggered() ui->label_6->setText(tr ("Band Activity")); ui->label_7->setText(tr ("Rx Frequency")); WSPR_config(false); -// 012345678901234567890123456789012345 - displayWidgets(nWidgets("111111000100111000010000000100000011")); + if(m_config.single_decode()) { +// 012345678901234567890123456789012345 + displayWidgets(nWidgets("111111000100111000010000000100000000")); + m_wideGraph->setSingleDecode(true); + } else { + displayWidgets(nWidgets("111111000100111000010000000100000011")); + m_wideGraph->setSingleDecode(false); + } setup_status_bar(false); ui->sbTR->values ({15, 30, 60, 120, 300, 900, 1800}); on_sbTR_valueChanged (ui->sbTR->value()); @@ -6649,6 +6660,13 @@ void MainWindow::on_sbF_High_valueChanged(int n) void MainWindow::chk_FST4_freq_range() { +// qDebug() << "aa" << m_wideGraph->nStartFreq() << m_wideGraph->Fmax() +// << ui->sbF_Low->value() << ui->sbF_High->value(); + if(ui->sbF_Low->value() < m_wideGraph->nStartFreq()) ui->sbF_Low->setValue(m_wideGraph->nStartFreq()); + if(ui->sbF_High->value() > m_wideGraph->Fmax()) { + int n=m_wideGraph->Fmax()/100; + ui->sbF_High->setValue(100*n); + } int maxDiff=2000; if(m_TRperiod==120) maxDiff=1000; if(m_TRperiod==300) maxDiff=400; diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index bc7b2270d..ab979af64 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -163,7 +163,6 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed) int iz=XfromFreq(5000.0); int jz=iz*m_binsPerPixel; m_fMax=FreqfromX(iz); - if(bScroll and swide[0]<1.e29) { flat4_(swide,&iz,&m_Flatten); if(!m_bReplot) flat4_(&dec_data.savg[j0],&jz,&m_Flatten); @@ -506,7 +505,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() or m_mode=="QRA64" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { - if(m_mode=="FST4") { + if(m_mode=="FST4" and !m_bSingleDecode) { x1=XfromFreq(m_nfa); x2=XfromFreq(m_nfb); painter0.drawLine(x1,25,x1+5,30); // Mark FST4 F_Low @@ -663,7 +662,9 @@ void CPlotter::setPlot2dZero(int plot2dZero) //setPlot2dZero void CPlotter::setStartFreq(int f) //SetStartFreq() { m_startFreq=f; + m_fMax=FreqfromX(XfromFreq(5000.0)); resizeEvent(NULL); + DrawOverlay(); update(); } @@ -684,6 +685,7 @@ void CPlotter::setRxRange(int fMin) //setRxRange void CPlotter::setBinsPerPixel(int n) //setBinsPerPixel { m_binsPerPixel = n; + m_fMax=FreqfromX(XfromFreq(5000.0)); DrawOverlay(); //Redraw scales and ticks update(); //trigger a new paintEvent} } @@ -824,8 +826,15 @@ void CPlotter::setFST4_FreqRange(int fLow,int fHigh) m_nfa=fLow; m_nfb=fHigh; DrawOverlay(); + update(); } +void CPlotter::setSingleDecode(bool b) +{ + m_bSingleDecode=b; +} + + void CPlotter::setColours(QVector const& cl) { g_ColorTbl = cl; diff --git a/widgets/plotter.h b/widgets/plotter.h index 3787fafe0..ac13b5408 100644 --- a/widgets/plotter.h +++ b/widgets/plotter.h @@ -84,7 +84,7 @@ public: void setVHF(bool bVHF); void setRedFile(QString fRed); void setFST4_FreqRange(int fLow,int fHigh); - + void setSingleDecode(bool b); bool scaleOK () const {return m_bScaleOK;} signals: @@ -114,6 +114,7 @@ private: bool m_bReference; bool m_bReference0; bool m_bVHF; + bool m_bSingleDecode; float m_fSpan; diff --git a/widgets/widegraph.cpp b/widgets/widegraph.cpp index 389986c84..a369f6296 100644 --- a/widgets/widegraph.cpp +++ b/widgets/widegraph.cpp @@ -505,6 +505,11 @@ void WideGraph::setFST4_FreqRange(int fLow,int fHigh) ui->widePlot->setFST4_FreqRange(fLow,fHigh); } +void WideGraph::setSingleDecode(bool b) +{ + ui->widePlot->setSingleDecode(b); +} + void WideGraph::on_smoSpinBox_valueChanged(int n) { m_nsmo=n; diff --git a/widgets/widegraph.h b/widgets/widegraph.h index d26328fdb..f5f70c281 100644 --- a/widgets/widegraph.h +++ b/widgets/widegraph.h @@ -50,6 +50,7 @@ public: void setVHF(bool bVHF); void setRedFile(QString fRed); void setFST4_FreqRange(int fLow,int fHigh); + void setSingleDecode(bool b); signals: void freezeDecode2(int n); From 41aa5dae745b81c4a0567a889cd38c90d83562b2 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 17 Sep 2020 12:58:59 -0400 Subject: [PATCH 04/16] Make the FTol control invisible in FST4 if Single decode is not checked. --- widgets/mainwindow.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 7d81f6868..4458aa8b2 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -2981,7 +2981,7 @@ void MainWindow::on_DecodeButton_clicked (bool /* checked */) //Decode request void MainWindow::freezeDecode(int n) //freezeDecode() { if((n%100)==2) { - if(m_mode=="FST4") ui->sbFtol->setValue(10); + if(m_mode=="FST4" and m_config.single_decode() and ui->sbFtol->value()>10) ui->sbFtol->setValue(10); on_DecodeButton_clicked (true); } } @@ -5926,8 +5926,9 @@ void MainWindow::on_actionFST4_triggered() displayWidgets(nWidgets("111111000100111000010000000100000000")); m_wideGraph->setSingleDecode(true); } else { - displayWidgets(nWidgets("111111000100111000010000000100000011")); + displayWidgets(nWidgets("111011000100111000010000000100000011")); m_wideGraph->setSingleDecode(false); + ui->sbFtol->setValue(20); } setup_status_bar(false); ui->sbTR->values ({15, 30, 60, 120, 300, 900, 1800}); @@ -6660,8 +6661,6 @@ void MainWindow::on_sbF_High_valueChanged(int n) void MainWindow::chk_FST4_freq_range() { -// qDebug() << "aa" << m_wideGraph->nStartFreq() << m_wideGraph->Fmax() -// << ui->sbF_Low->value() << ui->sbF_High->value(); if(ui->sbF_Low->value() < m_wideGraph->nStartFreq()) ui->sbF_Low->setValue(m_wideGraph->nStartFreq()); if(ui->sbF_High->value() > m_wideGraph->Fmax()) { int n=m_wideGraph->Fmax()/100; From 7d58df4cc1f128d8ec23e0682fd4753e33902130 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Thu, 17 Sep 2020 14:22:38 -0500 Subject: [PATCH 05/16] In FST4 mode with Single Decode not checked, move candidates within 20 Hz of nfqso to the top of the list. --- lib/fst4_decode.f90 | 74 ++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index a4cce0dcd..257705510 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -30,8 +30,8 @@ module fst4_decode contains subroutine decode(this,callback,iwave,nutc,nQSOProgress,nfa,nfb,nfqso, & - ndepth,ntrperiod,nexp_decode,ntol,emedelay,lapcqonly,mycall, & - hiscall,iwspr) + ndepth,ntrperiod,nexp_decode,ntol,emedelay,lapcqonly,mycall, & + hiscall,iwspr) use timer_module, only: timer use packjt77 @@ -49,7 +49,7 @@ contains complex, allocatable :: cframe(:) complex, allocatable :: c_bigfft(:) !Complex waveform real llr(240),llrs(240,4) - real candidates(200,5) + real candidates0(200,5),candidates(200,5) real bitmetrics(320,4) real s4(0:3,NN) real minsync @@ -232,19 +232,29 @@ contains nhicoh=1 nsyncoh=8 - fa=nfa - fb=nfb single_decode=iand(nexp_decode,32).ne.0 - if(single_decode) then - fa=max(100,nint(nfqso+1.5*baud-ntol)) + if(iwspr.eq.1) then !FST4W + nfa=max(100,nint(nfqso+1.5*baud-150)) ! 300 Hz wide noise-fit window + nfb=min(4800,nint(nfqso+1.5*baud+150)) + fa=max(100,nint(nfqso+1.5*baud-ntol)) ! signal search window fb=min(4800,nint(nfqso+1.5*baud+ntol)) + else if(single_decode) then + fa=max(100,nint(nfa+1.5*baud)) + fb=min(4800,nint(nfb+1.5*baud)) + nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window + nfb=min(4800,nfb+100) + else + fa=max(100,nint(nfa+1.5*baud)) + fb=min(4800,nint(nfb+1.5*baud)) + nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window + nfb=min(4800,nfb+100) endif minsync=1.20 if(ntrperiod.eq.15) minsync=1.15 ! Get first approximation of candidate frequencies call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb,nfa,nfb, & - minsync,ncand,candidates) + minsync,ncand,candidates0) ndecodes=0 decodes=' ' @@ -252,8 +262,8 @@ contains isbest=0 fc2=0. do icand=1,ncand - fc0=candidates(icand,1) - detmet=candidates(icand,2) + fc0=candidates0(icand,1) + detmet=candidates0(icand,2) ! Downconvert and downsample a slice of the spectrum centered on the ! rough estimate of the candidates frequency. @@ -270,35 +280,56 @@ contains fc_synced = fc0 + fcbest dt_synced = (isbest-fs2)*dt2 !nominal dt is 1 second so frame starts at sample fs2 - candidates(icand,3)=fc_synced - candidates(icand,4)=isbest + candidates0(icand,3)=fc_synced + candidates0(icand,4)=isbest enddo ! remove duplicate candidates do icand=1,ncand - fc=candidates(icand,3) - isbest=nint(candidates(icand,4)) + fc=candidates0(icand,3) + isbest=nint(candidates0(icand,4)) do ic2=1,ncand - fc2=candidates(ic2,3) - isbest2=nint(candidates(ic2,4)) + fc2=candidates0(ic2,3) + isbest2=nint(candidates0(ic2,4)) if(ic2.ne.icand .and. fc2.gt.0.0) then if(abs(fc2-fc).lt.0.10*baud) then ! same frequency if(abs(isbest2-isbest).le.2) then - candidates(ic2,3)=-1 + candidates0(ic2,3)=-1 endif endif endif enddo enddo - ic=0 do icand=1,ncand - if(candidates(icand,3).gt.0) then + if(candidates0(icand,3).gt.0) then ic=ic+1 - candidates(ic,:)=candidates(icand,:) + candidates0(ic,:)=candidates0(icand,:) endif enddo ncand=ic + +! If FST4 and Single Decode is not checked, then find candidates within +! 20 Hz of nfqso and put them at the top of the list + if(iwspr.eq.0 .and. .not.single_decode) then + nclose=count(abs(candidates0(:,3)-(nfqso+1.5*baud)).le.20) + k=0 + do i=1,ncand + if(abs(candidates0(i,3)-(nfqso+1.5*baud)).le.20) then + k=k+1 + candidates(k,:)=candidates0(i,:) + endif + enddo + do i=1,ncand + if(abs(candidates0(i,3)-(nfqso+1.5*baud)).gt.20) then + k=k+1 + candidates(k,:)=candidates0(i,:) + endif + enddo + else + candidates=candidates0 + endif + xsnr=0. !write(*,*) 'ncand ',ncand do icand=1,ncand @@ -307,7 +338,7 @@ contains isbest=nint(candidates(icand,4)) xdt=(isbest-nspsec)/fs2 if(ntrperiod.eq.15) xdt=(isbest-real(nspsec)/2.0)/fs2 - +! write(*,*) icand,sync,fc_synced,isbest,xdt call timer('dwnsmpl ',0) call fst4_downsample(c_bigfft,nfft1,ndown,fc_synced,sigbw,c2) call timer('dwnsmpl ',1) @@ -654,6 +685,7 @@ contains inb=nint(min(4800.0,real(nfb))/df2) !High freq limit for noise fit if(ia.lt.ina) ia=ina if(ib.gt.inb) ib=inb + nnw=nint(48000.*nsps*2./fs) allocate (s(nnw)) s=0. !Compute low-resolution power spectrum From bcf7f36b9c0148e9cb3cf5c9ad3f10de6c5c838b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 17 Sep 2020 19:28:55 -0400 Subject: [PATCH 06/16] Very basic code (including some diagnostics) for "try all NB settings". Will remove it again. --- lib/decoder.f90 | 8 ++++---- lib/fst4_decode.f90 | 29 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 0c4da1674..14bab01a6 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -199,8 +199,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) call timer('dec240 ',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & - params%nfqso,ndepth,params%ntr, & - params%nexp_decode,params%ntol,params%emedelay, & + params%nfqso,ndepth,params%ntr,params%nexp_decode, & + params%ntol,params%emedelay,logical(params%nagain), & logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 @@ -213,8 +213,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) call timer('dec240 ',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & - params%nfqso,ndepth,params%ntr, & - params%nexp_decode,params%ntol,params%emedelay, & + params%nfqso,ndepth,params%ntr,params%nexp_decode, & + params%ntol,params%emedelay,logical(params%nagain), & logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 257705510..577613c7f 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -30,7 +30,7 @@ module fst4_decode contains subroutine decode(this,callback,iwave,nutc,nQSOProgress,nfa,nfb,nfqso, & - ndepth,ntrperiod,nexp_decode,ntol,emedelay,lapcqonly,mycall, & + ndepth,ntrperiod,nexp_decode,ntol,emedelay,lagain,lapcqonly,mycall, & hiscall,iwspr) use timer_module, only: timer @@ -53,9 +53,10 @@ contains real bitmetrics(320,4) real s4(0:3,NN) real minsync - logical lapcqonly + logical lagain,lapcqonly integer itone(NN) integer hmod + integer ipct(0:7) integer*1 apmask(240),cw(240) integer*1 message101(101),message74(74),message77(77) integer*1 rvec(77) @@ -69,6 +70,7 @@ contains integer*2 iwave(30*60*12000) + data ipct/0,8,14,4,12,2,10,6/ data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ @@ -223,7 +225,23 @@ contains endif ndropmax=1 - npct=nexp_decode/256 + single_decode=iand(nexp_decode,32).ne.0 + inb0=0 + inb1=0 + if((single_decode .or. lagain) .and. (ntol.le.20 .or. iwspr.ne.0)) then + inb1=20 + else + ipct(0)=nexp_decode/256 + endif + + ndecodes=0 + decodes=' ' + + do inb=inb0,inb1,2 +! npct=ipct(inb) + npct=inb + write(*,3001) inb,inb1,lagain,single_decode,npct,ntol +3001 format(2i4,2L3,2i5) call blanker(iwave,nfft1,ndropmax,npct,c_bigfft) ! The big fft is done once and is used for calculating the smoothed spectrum @@ -232,7 +250,6 @@ contains nhicoh=1 nsyncoh=8 - single_decode=iand(nexp_decode,32).ne.0 if(iwspr.eq.1) then !FST4W nfa=max(100,nint(nfqso+1.5*baud-150)) ! 300 Hz wide noise-fit window nfb=min(4800,nint(nfqso+1.5*baud+150)) @@ -256,9 +273,6 @@ contains call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb,nfa,nfb, & minsync,ncand,candidates0) - ndecodes=0 - decodes=' ' - isbest=0 fc2=0. do icand=1,ncand @@ -510,6 +524,7 @@ contains enddo ! metrics enddo ! istart jitter 2002 enddo !candidate list + enddo return end subroutine decode From 033cc65d08da9610457983ead77411b80ad89801 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 17 Sep 2020 19:30:07 -0400 Subject: [PATCH 07/16] Revert "Very basic code (including some diagnostics) for "try all NB settings". Will remove it again." This reverts commit bcf7f36b9c0148e9cb3cf5c9ad3f10de6c5c838b. --- lib/decoder.f90 | 8 ++++---- lib/fst4_decode.f90 | 29 +++++++---------------------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 14bab01a6..0c4da1674 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -199,8 +199,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) call timer('dec240 ',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & - params%nfqso,ndepth,params%ntr,params%nexp_decode, & - params%ntol,params%emedelay,logical(params%nagain), & + params%nfqso,ndepth,params%ntr, & + params%nexp_decode,params%ntol,params%emedelay, & logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 @@ -213,8 +213,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) call timer('dec240 ',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & - params%nfqso,ndepth,params%ntr,params%nexp_decode, & - params%ntol,params%emedelay,logical(params%nagain), & + params%nfqso,ndepth,params%ntr, & + params%nexp_decode,params%ntol,params%emedelay, & logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 577613c7f..257705510 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -30,7 +30,7 @@ module fst4_decode contains subroutine decode(this,callback,iwave,nutc,nQSOProgress,nfa,nfb,nfqso, & - ndepth,ntrperiod,nexp_decode,ntol,emedelay,lagain,lapcqonly,mycall, & + ndepth,ntrperiod,nexp_decode,ntol,emedelay,lapcqonly,mycall, & hiscall,iwspr) use timer_module, only: timer @@ -53,10 +53,9 @@ contains real bitmetrics(320,4) real s4(0:3,NN) real minsync - logical lagain,lapcqonly + logical lapcqonly integer itone(NN) integer hmod - integer ipct(0:7) integer*1 apmask(240),cw(240) integer*1 message101(101),message74(74),message77(77) integer*1 rvec(77) @@ -70,7 +69,6 @@ contains integer*2 iwave(30*60*12000) - data ipct/0,8,14,4,12,2,10,6/ data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ @@ -225,23 +223,7 @@ contains endif ndropmax=1 - single_decode=iand(nexp_decode,32).ne.0 - inb0=0 - inb1=0 - if((single_decode .or. lagain) .and. (ntol.le.20 .or. iwspr.ne.0)) then - inb1=20 - else - ipct(0)=nexp_decode/256 - endif - - ndecodes=0 - decodes=' ' - - do inb=inb0,inb1,2 -! npct=ipct(inb) - npct=inb - write(*,3001) inb,inb1,lagain,single_decode,npct,ntol -3001 format(2i4,2L3,2i5) + npct=nexp_decode/256 call blanker(iwave,nfft1,ndropmax,npct,c_bigfft) ! The big fft is done once and is used for calculating the smoothed spectrum @@ -250,6 +232,7 @@ contains nhicoh=1 nsyncoh=8 + single_decode=iand(nexp_decode,32).ne.0 if(iwspr.eq.1) then !FST4W nfa=max(100,nint(nfqso+1.5*baud-150)) ! 300 Hz wide noise-fit window nfb=min(4800,nint(nfqso+1.5*baud+150)) @@ -273,6 +256,9 @@ contains call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb,nfa,nfb, & minsync,ncand,candidates0) + ndecodes=0 + decodes=' ' + isbest=0 fc2=0. do icand=1,ncand @@ -524,7 +510,6 @@ contains enddo ! metrics enddo ! istart jitter 2002 enddo !candidate list - enddo return end subroutine decode From 375a869a51d88875802002921a786c7438185dea Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Sep 2020 09:01:51 -0400 Subject: [PATCH 08/16] Revert "Revert "Very basic code (including some diagnostics) for "try all NB settings". Will remove it again."" This reverts commit 033cc65d08da9610457983ead77411b80ad89801. --- lib/decoder.f90 | 8 ++++---- lib/fst4_decode.f90 | 29 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 0c4da1674..14bab01a6 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -199,8 +199,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) call timer('dec240 ',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & - params%nfqso,ndepth,params%ntr, & - params%nexp_decode,params%ntol,params%emedelay, & + params%nfqso,ndepth,params%ntr,params%nexp_decode, & + params%ntol,params%emedelay,logical(params%nagain), & logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 @@ -213,8 +213,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) call timer('dec240 ',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & - params%nfqso,ndepth,params%ntr, & - params%nexp_decode,params%ntol,params%emedelay, & + params%nfqso,ndepth,params%ntr,params%nexp_decode, & + params%ntol,params%emedelay,logical(params%nagain), & logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 257705510..577613c7f 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -30,7 +30,7 @@ module fst4_decode contains subroutine decode(this,callback,iwave,nutc,nQSOProgress,nfa,nfb,nfqso, & - ndepth,ntrperiod,nexp_decode,ntol,emedelay,lapcqonly,mycall, & + ndepth,ntrperiod,nexp_decode,ntol,emedelay,lagain,lapcqonly,mycall, & hiscall,iwspr) use timer_module, only: timer @@ -53,9 +53,10 @@ contains real bitmetrics(320,4) real s4(0:3,NN) real minsync - logical lapcqonly + logical lagain,lapcqonly integer itone(NN) integer hmod + integer ipct(0:7) integer*1 apmask(240),cw(240) integer*1 message101(101),message74(74),message77(77) integer*1 rvec(77) @@ -69,6 +70,7 @@ contains integer*2 iwave(30*60*12000) + data ipct/0,8,14,4,12,2,10,6/ data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ @@ -223,7 +225,23 @@ contains endif ndropmax=1 - npct=nexp_decode/256 + single_decode=iand(nexp_decode,32).ne.0 + inb0=0 + inb1=0 + if((single_decode .or. lagain) .and. (ntol.le.20 .or. iwspr.ne.0)) then + inb1=20 + else + ipct(0)=nexp_decode/256 + endif + + ndecodes=0 + decodes=' ' + + do inb=inb0,inb1,2 +! npct=ipct(inb) + npct=inb + write(*,3001) inb,inb1,lagain,single_decode,npct,ntol +3001 format(2i4,2L3,2i5) call blanker(iwave,nfft1,ndropmax,npct,c_bigfft) ! The big fft is done once and is used for calculating the smoothed spectrum @@ -232,7 +250,6 @@ contains nhicoh=1 nsyncoh=8 - single_decode=iand(nexp_decode,32).ne.0 if(iwspr.eq.1) then !FST4W nfa=max(100,nint(nfqso+1.5*baud-150)) ! 300 Hz wide noise-fit window nfb=min(4800,nint(nfqso+1.5*baud+150)) @@ -256,9 +273,6 @@ contains call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb,nfa,nfb, & minsync,ncand,candidates0) - ndecodes=0 - decodes=' ' - isbest=0 fc2=0. do icand=1,ncand @@ -510,6 +524,7 @@ contains enddo ! metrics enddo ! istart jitter 2002 enddo !candidate list + enddo return end subroutine decode From 52bdd57e577da8db8622f8a21d65da629795d7d7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Sep 2020 11:30:23 -0400 Subject: [PATCH 09/16] Implement NB=-1%, NB=-2%. Fix a startup problem with WideGraps's fMax value. --- lib/fst4_decode.f90 | 501 +++++++++++++++++++++-------------------- widgets/mainwindow.cpp | 13 +- widgets/mainwindow.h | 1 + widgets/mainwindow.ui | 97 ++++---- 4 files changed, 310 insertions(+), 302 deletions(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 577613c7f..c212a91d9 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -226,308 +226,311 @@ contains ndropmax=1 single_decode=iand(nexp_decode,32).ne.0 + npct=0 + nb=nexp_decode/256 - 2 + if(nb.ge.0) npct=nb inb0=0 - inb1=0 - if((single_decode .or. lagain) .and. (ntol.le.20 .or. iwspr.ne.0)) then - inb1=20 + inb1=20 + inb2=5 + if(nb.eq.-1) then + inb2=5 !Try NB = 0, 5, 10, 15, 20% + else if(nb.eq.-2) then + inb2=2 !Try NB = 0, 2, 4,... 20% else - ipct(0)=nexp_decode/256 + inb1=0 !Fixed NB value, 0 to 25% + ipct(0)=npct endif - ndecodes=0 decodes=' ' - do inb=inb0,inb1,2 -! npct=ipct(inb) + do inb=inb0,inb1,inb2 npct=inb - write(*,3001) inb,inb1,lagain,single_decode,npct,ntol -3001 format(2i4,2L3,2i5) - call blanker(iwave,nfft1,ndropmax,npct,c_bigfft) + call blanker(iwave,nfft1,ndropmax,npct,c_bigfft) ! The big fft is done once and is used for calculating the smoothed spectrum ! and also for downconverting/downsampling each candidate. - call four2a(c_bigfft,nfft1,1,-1,0) !r2c + call four2a(c_bigfft,nfft1,1,-1,0) !r2c - nhicoh=1 - nsyncoh=8 - if(iwspr.eq.1) then !FST4W - nfa=max(100,nint(nfqso+1.5*baud-150)) ! 300 Hz wide noise-fit window - nfb=min(4800,nint(nfqso+1.5*baud+150)) - fa=max(100,nint(nfqso+1.5*baud-ntol)) ! signal search window - fb=min(4800,nint(nfqso+1.5*baud+ntol)) - else if(single_decode) then - fa=max(100,nint(nfa+1.5*baud)) - fb=min(4800,nint(nfb+1.5*baud)) - nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window - nfb=min(4800,nfb+100) - else - fa=max(100,nint(nfa+1.5*baud)) - fb=min(4800,nint(nfb+1.5*baud)) - nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window - nfb=min(4800,nfb+100) - endif - minsync=1.20 - if(ntrperiod.eq.15) minsync=1.15 + nhicoh=1 + nsyncoh=8 + if(iwspr.eq.1) then !FST4W + nfa=max(100,nint(nfqso+1.5*baud-150)) !300 Hz wide noise-fit window + nfb=min(4800,nint(nfqso+1.5*baud+150)) + fa=max(100,nint(nfqso+1.5*baud-ntol)) ! signal search window + fb=min(4800,nint(nfqso+1.5*baud+ntol)) + else if(single_decode) then + fa=max(100,nint(nfa+1.5*baud)) + fb=min(4800,nint(nfb+1.5*baud)) + nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window + nfb=min(4800,nfb+100) + else + fa=max(100,nint(nfa+1.5*baud)) + fb=min(4800,nint(nfb+1.5*baud)) + nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window + nfb=min(4800,nfb+100) + endif + minsync=1.20 + if(ntrperiod.eq.15) minsync=1.15 ! Get first approximation of candidate frequencies - call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb,nfa,nfb, & - minsync,ncand,candidates0) + call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb,nfa,nfb, & + minsync,ncand,candidates0) - isbest=0 - fc2=0. - do icand=1,ncand - fc0=candidates0(icand,1) - detmet=candidates0(icand,2) + isbest=0 + fc2=0. + do icand=1,ncand + fc0=candidates0(icand,1) + if(iwspr.eq.0 .and. nb.lt.0 .and. & + abs(fc0-(nfqso+1.5*baud)).gt.ntol) cycle + detmet=candidates0(icand,2) ! Downconvert and downsample a slice of the spectrum centered on the ! rough estimate of the candidates frequency. ! Output array c2 is complex baseband sampled at 12000/ndown Sa/sec. ! The size of the downsampled c2 array is nfft2=nfft1/ndown - call timer('dwnsmpl ',0) - call fst4_downsample(c_bigfft,nfft1,ndown,fc0,sigbw,c2) - call timer('dwnsmpl ',1) + call timer('dwnsmpl ',0) + call fst4_downsample(c_bigfft,nfft1,ndown,fc0,sigbw,c2) + call timer('dwnsmpl ',1) - call timer('sync240 ',0) - call fst4_sync_search(c2,nfft2,hmod,fs2,nss,ntrperiod,nsyncoh,emedelay,sbest,fcbest,isbest) - call timer('sync240 ',1) + call timer('sync240 ',0) + call fst4_sync_search(c2,nfft2,hmod,fs2,nss,ntrperiod,nsyncoh,emedelay,sbest,fcbest,isbest) + call timer('sync240 ',1) - fc_synced = fc0 + fcbest - dt_synced = (isbest-fs2)*dt2 !nominal dt is 1 second so frame starts at sample fs2 - candidates0(icand,3)=fc_synced - candidates0(icand,4)=isbest - enddo + fc_synced = fc0 + fcbest + dt_synced = (isbest-fs2)*dt2 !nominal dt is 1 second so frame starts at sample fs2 + candidates0(icand,3)=fc_synced + candidates0(icand,4)=isbest + enddo ! remove duplicate candidates - do icand=1,ncand - fc=candidates0(icand,3) - isbest=nint(candidates0(icand,4)) - do ic2=1,ncand - fc2=candidates0(ic2,3) - isbest2=nint(candidates0(ic2,4)) - if(ic2.ne.icand .and. fc2.gt.0.0) then - if(abs(fc2-fc).lt.0.10*baud) then ! same frequency - if(abs(isbest2-isbest).le.2) then - candidates0(ic2,3)=-1 + do icand=1,ncand + fc=candidates0(icand,3) + isbest=nint(candidates0(icand,4)) + do ic2=1,ncand + fc2=candidates0(ic2,3) + isbest2=nint(candidates0(ic2,4)) + if(ic2.ne.icand .and. fc2.gt.0.0) then + if(abs(fc2-fc).lt.0.10*baud) then ! same frequency + if(abs(isbest2-isbest).le.2) then + candidates0(ic2,3)=-1 + endif endif endif + enddo + enddo + ic=0 + do icand=1,ncand + if(candidates0(icand,3).gt.0) then + ic=ic+1 + candidates0(ic,:)=candidates0(icand,:) endif enddo - enddo - ic=0 - do icand=1,ncand - if(candidates0(icand,3).gt.0) then - ic=ic+1 - candidates0(ic,:)=candidates0(icand,:) - endif - enddo - ncand=ic + ncand=ic ! If FST4 and Single Decode is not checked, then find candidates within ! 20 Hz of nfqso and put them at the top of the list - if(iwspr.eq.0 .and. .not.single_decode) then - nclose=count(abs(candidates0(:,3)-(nfqso+1.5*baud)).le.20) - k=0 - do i=1,ncand - if(abs(candidates0(i,3)-(nfqso+1.5*baud)).le.20) then - k=k+1 - candidates(k,:)=candidates0(i,:) - endif - enddo - do i=1,ncand - if(abs(candidates0(i,3)-(nfqso+1.5*baud)).gt.20) then - k=k+1 - candidates(k,:)=candidates0(i,:) - endif - enddo - else - candidates=candidates0 - endif - - xsnr=0. -!write(*,*) 'ncand ',ncand - do icand=1,ncand - sync=candidates(icand,2) - fc_synced=candidates(icand,3) - isbest=nint(candidates(icand,4)) - xdt=(isbest-nspsec)/fs2 - if(ntrperiod.eq.15) xdt=(isbest-real(nspsec)/2.0)/fs2 -! write(*,*) icand,sync,fc_synced,isbest,xdt - call timer('dwnsmpl ',0) - call fst4_downsample(c_bigfft,nfft1,ndown,fc_synced,sigbw,c2) - call timer('dwnsmpl ',1) - - do ijitter=0,jittermax - if(ijitter.eq.0) ioffset=0 - if(ijitter.eq.1) ioffset=1 - if(ijitter.eq.2) ioffset=-1 - is0=isbest+ioffset - if(is0.lt.0) cycle - cframe=c2(is0:is0+160*nss-1) - bitmetrics=0 - call timer('bitmetrc',0) - call get_fst4_bitmetrics(cframe,nss,nblock,nhicoh,bitmetrics, & - s4,nsync_qual,badsync) - call timer('bitmetrc',1) - if(badsync) cycle - - do il=1,4 - llrs( 1: 60,il)=bitmetrics( 17: 76, il) - llrs( 61:120,il)=bitmetrics( 93:152, il) - llrs(121:180,il)=bitmetrics(169:228, il) - llrs(181:240,il)=bitmetrics(245:304, il) + if(iwspr.eq.0 .and. .not.single_decode) then + nclose=count(abs(candidates0(:,3)-(nfqso+1.5*baud)).le.20) + k=0 + do i=1,ncand + if(abs(candidates0(i,3)-(nfqso+1.5*baud)).le.20) then + k=k+1 + candidates(k,:)=candidates0(i,:) + endif enddo + do i=1,ncand + if(abs(candidates0(i,3)-(nfqso+1.5*baud)).gt.20) then + k=k+1 + candidates(k,:)=candidates0(i,:) + endif + enddo + else + candidates=candidates0 + endif - apmag=maxval(abs(llrs(:,1)))*1.1 - ntmax=nblock+nappasses(nQSOProgress) - if(lapcqonly) ntmax=nblock+1 - if(ndepth.eq.1) ntmax=nblock - apmask=0 + xsnr=0. + do icand=1,ncand + sync=candidates(icand,2) + fc_synced=candidates(icand,3) + isbest=nint(candidates(icand,4)) + xdt=(isbest-nspsec)/fs2 + if(ntrperiod.eq.15) xdt=(isbest-real(nspsec)/2.0)/fs2 + call timer('dwnsmpl ',0) + call fst4_downsample(c_bigfft,nfft1,ndown,fc_synced,sigbw,c2) + call timer('dwnsmpl ',1) - if(iwspr.eq.1) then ! 50-bit msgs, no ap decoding - nblock=4 - ntmax=nblock - endif + do ijitter=0,jittermax + if(ijitter.eq.0) ioffset=0 + if(ijitter.eq.1) ioffset=1 + if(ijitter.eq.2) ioffset=-1 + is0=isbest+ioffset + if(is0.lt.0) cycle + cframe=c2(is0:is0+160*nss-1) + bitmetrics=0 + call timer('bitmetrc',0) + call get_fst4_bitmetrics(cframe,nss,nblock,nhicoh,bitmetrics, & + s4,nsync_qual,badsync) + call timer('bitmetrc',1) + if(badsync) cycle - do itry=1,ntmax - if(itry.eq.1) llr=llrs(:,1) - if(itry.eq.2.and.itry.le.nblock) llr=llrs(:,2) - if(itry.eq.3.and.itry.le.nblock) llr=llrs(:,3) - if(itry.eq.4.and.itry.le.nblock) llr=llrs(:,4) - if(itry.le.nblock) then - apmask=0 - iaptype=0 + do il=1,4 + llrs( 1: 60,il)=bitmetrics( 17: 76, il) + llrs( 61:120,il)=bitmetrics( 93:152, il) + llrs(121:180,il)=bitmetrics(169:228, il) + llrs(181:240,il)=bitmetrics(245:304, il) + enddo + + apmag=maxval(abs(llrs(:,1)))*1.1 + ntmax=nblock+nappasses(nQSOProgress) + if(lapcqonly) ntmax=nblock+1 + if(ndepth.eq.1) ntmax=nblock + apmask=0 + + if(iwspr.eq.1) then ! 50-bit msgs, no ap decoding + nblock=4 + ntmax=nblock endif - if(itry.gt.nblock) then ! do ap passes - llr=llrs(:,nblock) ! Use largest blocksize as the basis for AP passes - iaptype=naptypes(nQSOProgress,itry-nblock) - if(lapcqonly) iaptype=1 - if(iaptype.ge.2 .and. apbits(1).gt.1) cycle ! No, or nonstandard, mycall - if(iaptype.ge.3 .and. apbits(30).gt.1) cycle ! No, or nonstandard, dxcall - if(iaptype.eq.1) then ! CQ + do itry=1,ntmax + if(itry.eq.1) llr=llrs(:,1) + if(itry.eq.2.and.itry.le.nblock) llr=llrs(:,2) + if(itry.eq.3.and.itry.le.nblock) llr=llrs(:,3) + if(itry.eq.4.and.itry.le.nblock) llr=llrs(:,4) + if(itry.le.nblock) then apmask=0 - apmask(1:29)=1 - llr(1:29)=apmag*mcq(1:29) + iaptype=0 endif - if(iaptype.eq.2) then ! MyCall ??? ??? - apmask=0 - apmask(1:29)=1 - llr(1:29)=apmag*apbits(1:29) - endif + if(itry.gt.nblock) then ! do ap passes + llr=llrs(:,nblock) ! Use largest blocksize as the basis for AP passes + iaptype=naptypes(nQSOProgress,itry-nblock) + if(lapcqonly) iaptype=1 + if(iaptype.ge.2 .and. apbits(1).gt.1) cycle ! No, or nonstandard, mycall + if(iaptype.ge.3 .and. apbits(30).gt.1) cycle ! No, or nonstandard, dxcall + if(iaptype.eq.1) then ! CQ + apmask=0 + apmask(1:29)=1 + llr(1:29)=apmag*mcq(1:29) + endif - if(iaptype.eq.3) then ! MyCall DxCall ??? - apmask=0 - apmask(1:58)=1 - llr(1:58)=apmag*apbits(1:58) - endif + if(iaptype.eq.2) then ! MyCall ??? ??? + apmask=0 + apmask(1:29)=1 + llr(1:29)=apmag*apbits(1:29) + endif - if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype .eq.6) then - apmask=0 - apmask(1:77)=1 - llr(1:58)=apmag*apbits(1:58) - if(iaptype.eq.4) llr(59:77)=apmag*mrrr(1:19) - if(iaptype.eq.5) llr(59:77)=apmag*m73(1:19) - if(iaptype.eq.6) llr(59:77)=apmag*mrr73(1:19) - endif - endif - - dmin=0.0 - nharderrors=-1 - unpk77_success=.false. - if(iwspr.eq.0) then - maxosd=2 - Keff=91 - norder=3 - call timer('d240_101',0) - call decode240_101(llr,Keff,maxosd,norder,apmask,message101, & - cw,ntype,nharderrors,dmin) - call timer('d240_101',1) - elseif(iwspr.eq.1) then - maxosd=2 - call timer('d240_74 ',0) - Keff=64 - norder=4 - call decode240_74(llr,Keff,maxosd,norder,apmask,message74,cw, & - ntype,nharderrors,dmin) - call timer('d240_74 ',1) - endif - - if(nharderrors .ge.0) then - if(count(cw.eq.1).eq.0) then - nharderrors=-nharderrors - cycle + if(iaptype.eq.3) then ! MyCall DxCall ??? + apmask=0 + apmask(1:58)=1 + llr(1:58)=apmag*apbits(1:58) + endif + + if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype .eq.6) then + apmask=0 + apmask(1:77)=1 + llr(1:58)=apmag*apbits(1:58) + if(iaptype.eq.4) llr(59:77)=apmag*mrrr(1:19) + if(iaptype.eq.5) llr(59:77)=apmag*m73(1:19) + if(iaptype.eq.6) llr(59:77)=apmag*mrr73(1:19) + endif endif + + dmin=0.0 + nharderrors=-1 + unpk77_success=.false. if(iwspr.eq.0) then - write(c77,'(77i1)') mod(message101(1:77)+rvec,2) - call unpack77(c77,1,msg,unpk77_success) - else - write(c77,'(50i1)') message74(1:50) - c77(51:77)='000000000000000000000110000' - call unpack77(c77,1,msg,unpk77_success) + maxosd=2 + Keff=91 + norder=3 + call timer('d240_101',0) + call decode240_101(llr,Keff,maxosd,norder,apmask,message101, & + cw,ntype,nharderrors,dmin) + call timer('d240_101',1) + elseif(iwspr.eq.1) then + maxosd=2 + call timer('d240_74 ',0) + Keff=64 + norder=4 + call decode240_74(llr,Keff,maxosd,norder,apmask,message74,cw, & + ntype,nharderrors,dmin) + call timer('d240_74 ',1) endif - if(unpk77_success) then - idupe=0 - do i=1,ndecodes - if(decodes(i).eq.msg) idupe=1 - enddo - if(idupe.eq.1) goto 2002 - ndecodes=ndecodes+1 - decodes(ndecodes)=msg - + + if(nharderrors .ge.0) then + if(count(cw.eq.1).eq.0) then + nharderrors=-nharderrors + cycle + endif if(iwspr.eq.0) then - call get_fst4_tones_from_bits(message101,itone,0) + write(c77,'(77i1)') mod(message101(1:77)+rvec,2) + call unpack77(c77,1,msg,unpk77_success) else - call get_fst4_tones_from_bits(message74,itone,1) + write(c77,'(50i1)') message74(1:50) + c77(51:77)='000000000000000000000110000' + call unpack77(c77,1,msg,unpk77_success) endif - inquire(file='plotspec',exist=ex) - fmid=-999.0 - call timer('dopsprd ',0) + if(unpk77_success) then + idupe=0 + do i=1,ndecodes + if(decodes(i).eq.msg) idupe=1 + enddo + if(idupe.eq.1) goto 2002 + ndecodes=ndecodes+1 + decodes(ndecodes)=msg + + if(iwspr.eq.0) then + call get_fst4_tones_from_bits(message101,itone,0) + else + call get_fst4_tones_from_bits(message74,itone,1) + endif + inquire(file='plotspec',exist=ex) + fmid=-999.0 + call timer('dopsprd ',0) + if(ex) then + call dopspread(itone,iwave,nsps,nmax,ndown,hmod, & + isbest,fc_synced,fmid,w50) + endif + call timer('dopsprd ',1) + xsig=0 + do i=1,NN + xsig=xsig+s4(itone(i),i) + enddo + base=candidates(icand,5) + arg=600.0*(xsig/base)-1.0 + if(arg.gt.0.0) then + xsnr=10*log10(arg)-35.5-12.5*log10(nsps/8200.0) + if(ntrperiod.eq. 15) xsnr=xsnr+2 + if(ntrperiod.eq. 30) xsnr=xsnr+1 + if(ntrperiod.eq. 900) xsnr=xsnr+1 + if(ntrperiod.eq.1800) xsnr=xsnr+2 + else + xsnr=-99.9 + endif + else + cycle + endif + nsnr=nint(xsnr) + qual=0. + fsig=fc_synced - 1.5*baud if(ex) then - call dopspread(itone,iwave,nsps,nmax,ndown,hmod, & - isbest,fc_synced,fmid,w50) + write(21,3021) nutc,icand,itry,nsyncoh,iaptype, & + ijitter,ntype,nsync_qual,nharderrors,dmin, & + sync,xsnr,xdt,fsig,w50,trim(msg) +3021 format(i6.6,6i3,2i4,f6.1,f7.2,f6.1,f6.2,f7.1,f7.3,1x,a) + flush(21) endif - call timer('dopsprd ',1) - xsig=0 - do i=1,NN - xsig=xsig+s4(itone(i),i) - enddo - base=candidates(icand,5) - arg=600.0*(xsig/base)-1.0 - if(arg.gt.0.0) then - xsnr=10*log10(arg)-35.5-12.5*log10(nsps/8200.0) - if(ntrperiod.eq. 15) xsnr=xsnr+2 - if(ntrperiod.eq. 30) xsnr=xsnr+1 - if(ntrperiod.eq. 900) xsnr=xsnr+1 - if(ntrperiod.eq.1800) xsnr=xsnr+2 - else - xsnr=-99.9 - endif - else - cycle + call this%callback(nutc,smax1,nsnr,xdt,fsig,msg, & + iaptype,qual,ntrperiod,lwspr,fmid,w50) + goto 2002 endif - nsnr=nint(xsnr) - qual=0. - fsig=fc_synced - 1.5*baud - if(ex) then - write(21,3021) nutc,icand,itry,nsyncoh,iaptype, & - ijitter,ntype,nsync_qual,nharderrors,dmin, & - sync,xsnr,xdt,fsig,w50,trim(msg) -3021 format(i6.6,6i3,2i4,f6.1,f7.2,f6.1,f6.2,f7.1,f7.3,1x,a) - flush(21) - endif - call this%callback(nutc,smax1,nsnr,xdt,fsig,msg, & - iaptype,qual,ntrperiod,lwspr,fmid,w50) - goto 2002 - endif - enddo ! metrics - enddo ! istart jitter -2002 enddo !candidate list + enddo ! metrics + enddo ! istart jitter +2002 enddo !candidate list enddo - + return - end subroutine decode + end subroutine decode subroutine sync_fst4(cd0,i0,f0,hmod,ncoh,np,nss,ntr,fs,sync) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 4458aa8b2..6f014b99a 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3127,7 +3127,7 @@ void MainWindow::decode() //decode() dec_data.params.nexp_decode = static_cast (m_config.special_op_id()); if(m_config.single_decode()) dec_data.params.nexp_decode += 32; if(m_config.enable_VHF_features()) dec_data.params.nexp_decode += 64; - if(m_mode.startsWith("FST4")) dec_data.params.nexp_decode += 256*ui->sbNB->value(); + if(m_mode.startsWith("FST4")) dec_data.params.nexp_decode += 256*(ui->sbNB->value()+2); ::memcpy(dec_data.params.datetime, m_dateTime.toLatin1()+" ", sizeof dec_data.params.datetime); ::memcpy(dec_data.params.mycall, (m_config.my_callsign()+" ").toLatin1(), sizeof dec_data.params.mycall); @@ -4241,7 +4241,7 @@ void MainWindow::guiUpdate() //Once per second (onesec) if(nsec != m_sec0) { // qDebug() << "AAA" << nsec; - if(m_mode=="FST4") chk_FST4_freq_range(); + if(m_mode=="FST4" and m_bOK_to_chk) chk_FST4_freq_range(); m_currentBand=m_config.bands()->find(m_freqNominal); if( SpecOp::HOUND == m_config.special_op_id() ) { qint32 tHound=QDateTime::currentMSecsSinceEpoch()/1000 - m_tAutoOn; @@ -5931,9 +5931,6 @@ void MainWindow::on_actionFST4_triggered() ui->sbFtol->setValue(20); } setup_status_bar(false); - ui->sbTR->values ({15, 30, 60, 120, 300, 900, 1800}); - on_sbTR_valueChanged (ui->sbTR->value()); - chk_FST4_freq_range(); ui->cbAutoSeq->setChecked(true); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); @@ -5942,9 +5939,13 @@ void MainWindow::on_actionFST4_triggered() m_wideGraph->setTol(ui->sbFtol->value()); m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); m_wideGraph->setFST4_FreqRange(ui->sbF_Low->value(),ui->sbF_High->value()); + chk_FST4_freq_range(); switch_mode (Modes::FST4); m_wideGraph->setMode(m_mode); + ui->sbTR->values ({15, 30, 60, 120, 300, 900, 1800}); + on_sbTR_valueChanged (ui->sbTR->value()); statusChanged(); + m_bOK_to_chk=true; } void MainWindow::on_actionFST4W_triggered() @@ -7528,7 +7529,7 @@ void MainWindow::on_sbTR_valueChanged(int value) m_wideGraph->setPeriod (value, m_nsps); progressBar.setMaximum (value); } - if(m_mode=="FST4") chk_FST4_freq_range(); + if(m_mode=="FST4" and m_bOK_to_chk) chk_FST4_freq_range(); if(m_monitoring) { on_stopButton_clicked(); on_monitorButton_clicked(true); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 264e0cac5..011e29945 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -527,6 +527,7 @@ private: bool m_bWarnedSplit=false; bool m_bTUmsg; bool m_bBestSPArmed=false; + bool m_bOK_to_chk=false; enum { diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 9779fe3bb..558fefe06 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -1018,28 +1018,6 @@ When not checked you can view the calibration results. - - - - Qt::AlignCenter - - - F Low - - - 100 - - - 5000 - - - 100 - - - 600 - - - @@ -1065,6 +1043,53 @@ When not checked you can view the calibration results. + + + + Qt::AlignCenter + + + F Low + + + 100 + + + 5000 + + + 100 + + + 600 + + + + + + + Audio Rx frequency + + + Qt::AlignCenter + + + Hz + + + Rx + + + 200 + + + 5000 + + + 1500 + + + @@ -1153,31 +1178,6 @@ When not checked you can view the calibration results. - - - - Audio Rx frequency - - - Qt::AlignCenter - - - Hz - - - Rx - - - 200 - - - 5000 - - - 1500 - - - @@ -2470,6 +2470,9 @@ Yellow when too low NB + + -2 + 25 From f0ed93cdd08390b20a27cfa2f9d7d4c46f63ae2a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Sep 2020 11:45:28 -0400 Subject: [PATCH 10/16] In the NB-loop, don't cycle around a decode attempt for the npct=0 pass. --- lib/fst4_decode.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index c212a91d9..b02cda862 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -280,7 +280,7 @@ contains fc2=0. do icand=1,ncand fc0=candidates0(icand,1) - if(iwspr.eq.0 .and. nb.lt.0 .and. & + if(iwspr.eq.0 .and. nb.lt.0 .and. npct.ne.0 .and. & abs(fc0-(nfqso+1.5*baud)).gt.ntol) cycle detmet=candidates0(icand,2) From 327808a0bb7d8e04b4d68a6c6e01925dde78cda7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Sep 2020 13:33:30 -0400 Subject: [PATCH 11/16] One more try at fixing the Fmax() startup problem that Steve sees. --- widgets/mainwindow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 6f014b99a..6b6bf4f08 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -4241,7 +4241,7 @@ void MainWindow::guiUpdate() //Once per second (onesec) if(nsec != m_sec0) { // qDebug() << "AAA" << nsec; - if(m_mode=="FST4" and m_bOK_to_chk) chk_FST4_freq_range(); + if(m_mode=="FST4") chk_FST4_freq_range(); m_currentBand=m_config.bands()->find(m_freqNominal); if( SpecOp::HOUND == m_config.special_op_id() ) { qint32 tHound=QDateTime::currentMSecsSinceEpoch()/1000 - m_tAutoOn; @@ -5946,6 +5946,7 @@ void MainWindow::on_actionFST4_triggered() on_sbTR_valueChanged (ui->sbTR->value()); statusChanged(); m_bOK_to_chk=true; + chk_FST4_freq_range(); } void MainWindow::on_actionFST4W_triggered() @@ -6662,6 +6663,7 @@ void MainWindow::on_sbF_High_valueChanged(int n) void MainWindow::chk_FST4_freq_range() { + if(!m_bOK_to_chk) return; if(ui->sbF_Low->value() < m_wideGraph->nStartFreq()) ui->sbF_Low->setValue(m_wideGraph->nStartFreq()); if(ui->sbF_High->value() > m_wideGraph->Fmax()) { int n=m_wideGraph->Fmax()/100; @@ -7529,7 +7531,7 @@ void MainWindow::on_sbTR_valueChanged(int value) m_wideGraph->setPeriod (value, m_nsps); progressBar.setMaximum (value); } - if(m_mode=="FST4" and m_bOK_to_chk) chk_FST4_freq_range(); + if(m_mode=="FST4") chk_FST4_freq_range(); if(m_monitoring) { on_stopButton_clicked(); on_monitorButton_clicked(true); From 2af01ebaa1253b372377d70b6dd745d0fc353002 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 18 Sep 2020 15:52:33 -0400 Subject: [PATCH 12/16] Fix a flaw in the loop-over NB logic. There are more flaws! --- lib/fst4_decode.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index b02cda862..dac3fcc32 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -244,7 +244,7 @@ contains decodes=' ' do inb=inb0,inb1,inb2 - npct=inb + if(nb.lt.0) npct=inb call blanker(iwave,nfft1,ndropmax,npct,c_bigfft) ! The big fft is done once and is used for calculating the smoothed spectrum From 0ab3e5116fffc2a670142215b7d290cbc7e6f1ae Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 19 Sep 2020 10:08:42 -0400 Subject: [PATCH 13/16] Fix several flaws in the loop-over-NB logic in the FST4 decoder. --- lib/fst4_decode.f90 | 64 +++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index dac3fcc32..e97d8f096 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -229,7 +229,6 @@ contains npct=0 nb=nexp_decode/256 - 2 if(nb.ge.0) npct=nb - inb0=0 inb1=20 inb2=5 if(nb.eq.-1) then @@ -240,42 +239,44 @@ contains inb1=0 !Fixed NB value, 0 to 25% ipct(0)=npct endif + + if(iwspr.eq.1) then !FST4W + !300 Hz wide noise-fit window + nfa=max(100,nint(nfqso+1.5*baud-150)) + nfb=min(4800,nint(nfqso+1.5*baud+150)) + fa=max(100,nint(nfqso+1.5*baud-ntol)) ! signal search window + fb=min(4800,nint(nfqso+1.5*baud+ntol)) + else if(single_decode) then + fa=max(100,nint(nfa+1.5*baud)) + fb=min(4800,nint(nfb+1.5*baud)) + ! extend noise fit 100 Hz outside of search window + nfa=max(100,nfa-100) + nfb=min(4800,nfb+100) + else + fa=max(100,nint(nfa+1.5*baud)) + fb=min(4800,nint(nfb+1.5*baud)) + ! extend noise fit 100 Hz outside of search window + nfa=max(100,nfa-100) + nfb=min(4800,nfb+100) + endif + ndecodes=0 decodes=' ' - - do inb=inb0,inb1,inb2 + do inb=0,inb1,inb2 if(nb.lt.0) npct=inb call blanker(iwave,nfft1,ndropmax,npct,c_bigfft) ! The big fft is done once and is used for calculating the smoothed spectrum ! and also for downconverting/downsampling each candidate. call four2a(c_bigfft,nfft1,1,-1,0) !r2c - nhicoh=1 nsyncoh=8 - if(iwspr.eq.1) then !FST4W - nfa=max(100,nint(nfqso+1.5*baud-150)) !300 Hz wide noise-fit window - nfb=min(4800,nint(nfqso+1.5*baud+150)) - fa=max(100,nint(nfqso+1.5*baud-ntol)) ! signal search window - fb=min(4800,nint(nfqso+1.5*baud+ntol)) - else if(single_decode) then - fa=max(100,nint(nfa+1.5*baud)) - fb=min(4800,nint(nfb+1.5*baud)) - nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window - nfb=min(4800,nfb+100) - else - fa=max(100,nint(nfa+1.5*baud)) - fb=min(4800,nint(nfb+1.5*baud)) - nfa=max(100,nfa-100) ! extend noise fit 100 Hz outside of search window - nfb=min(4800,nfb+100) - endif minsync=1.20 if(ntrperiod.eq.15) minsync=1.15 - + ! Get first approximation of candidate frequencies call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb,nfa,nfb, & - minsync,ncand,candidates0) - + minsync,ncand,candidates0) isbest=0 fc2=0. do icand=1,ncand @@ -307,10 +308,10 @@ contains do icand=1,ncand fc=candidates0(icand,3) isbest=nint(candidates0(icand,4)) - do ic2=1,ncand + do ic2=icand+1,ncand fc2=candidates0(ic2,3) isbest2=nint(candidates0(ic2,4)) - if(ic2.ne.icand .and. fc2.gt.0.0) then + if(fc2.gt.0.0) then if(abs(fc2-fc).lt.0.10*baud) then ! same frequency if(abs(isbest2-isbest).le.2) then candidates0(ic2,3)=-1 @@ -327,7 +328,7 @@ contains endif enddo ncand=ic - + ! If FST4 and Single Decode is not checked, then find candidates within ! 20 Hz of nfqso and put them at the top of the list if(iwspr.eq.0 .and. .not.single_decode) then @@ -475,7 +476,7 @@ contains do i=1,ndecodes if(decodes(i).eq.msg) idupe=1 enddo - if(idupe.eq.1) goto 2002 + if(idupe.eq.1) goto 800 ndecodes=ndecodes+1 decodes(ndecodes)=msg @@ -522,14 +523,15 @@ contains endif call this%callback(nutc,smax1,nsnr,xdt,fsig,msg, & iaptype,qual,ntrperiod,lwspr,fmid,w50) - goto 2002 + if(iwspr.eq.0 .and. nb.lt.0) go to 900 + goto 800 endif enddo ! metrics enddo ! istart jitter -2002 enddo !candidate list - enddo +800 enddo !candidate list + enddo ! noise blanker loop - return +900 return end subroutine decode subroutine sync_fst4(cd0,i0,f0,hmod,ncoh,np,nss,ntr,fs,sync) From e79c5f65766d71ddd9d8f67f4c9950a3d9ea6280 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 20 Sep 2020 10:16:08 -0400 Subject: [PATCH 14/16] Minor edits to User Guide. --- doc/user_guide/en/install-windows.adoc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/user_guide/en/install-windows.adoc b/doc/user_guide/en/install-windows.adoc index b999c15e7..19c73e3a3 100644 --- a/doc/user_guide/en/install-windows.adoc +++ b/doc/user_guide/en/install-windows.adoc @@ -21,19 +21,21 @@ TIP: Your computer may be configured so that this directory is `"%LocalAppData%\WSJT-X\"`. * The built-in Windows facility for time synchronization is usually - not adequate. We recommend the program _Meinberg NTP Client_ (see - {ntpsetup} for downloading and installation instructions). Recent + not adequate. We recommend the program _Meinberg NTP Client_: see + {ntpsetup} for downloading and installation instructions. Recent versions of Windows 10 are now shipped with a more capable Internet time synchronization service that is suitable if configured appropriately. We do not recommend SNTP time setting tools or others that make periodic correction steps, _WSJT-X_ requires that the PC - clock be monotonic. + clock be monotonically increasing and smoothly continuous. NOTE: Having a PC clock that appears to be synchronized to UTC is not - sufficient, monotonicity means that the clock must not be - stepped backwards or forwards during corrections, instead the - clock frequency must be adjusted to correct synchronization - errors gradually. + sufficient. "`Monotonically increasing`" means that the clock + must not be stepped backwards. "`Smoothly continuous`" means + that time must increase at a nearly constant rate, without + steps. Any necessary clock corrections must be applied by + adjusting the rate of increase, thereby correcting + synchronization errors gradually. [[OPENSSL]] From 1ab59a8d6b3f6363ec4287cbb9c73271b058dc35 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 20 Sep 2020 10:17:27 -0400 Subject: [PATCH 15/16] Fully configure WideGpahe after switching to JT65 mode. --- widgets/mainwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 6b6bf4f08..8b27440c5 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6297,6 +6297,9 @@ void MainWindow::on_actionJT65_triggered() m_wideGraph->setPeriod(m_TRperiod,m_nsps); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); + m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); + m_wideGraph->setTol(ui->sbFtol->value()); + m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); setup_status_bar (bVHF); m_bFastMode=false; m_bFast9=false; From 542ffe83112c16e9a56fe946c496c8b4973683ff Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 20 Sep 2020 18:20:16 +0100 Subject: [PATCH 16/16] Improve audio device handling and error recovery where possible audio devices that disappear are not forgotten until the user selects another device, this should allow temporarily missing devices or forgetting to switch on devices before starting WSJT-X to be handled more cleanly. If all else fails, visiting the Settings dialog and clicking OK should get things going again. Note that we still do not have a reliable way of detecting failed audio out devices, in that case selecting another device and then returning to the original should work. Enumerating audio devices is expensive and on Linux may take many seconds per device. To avoid lengthy blocking behaviour until it is absolutely necessary, audio devices are not enumerated until one of the "Settings->Audio" device drop-down lists is opened. Elsewhere when devices must be discovered the enumeration stops as soon as the configured device is discovered. A status bar message is posted when audio devices are being enumerated as a reminder that the UI may block while this is happening. The message box warning about unaccounted-for input audio samples now only triggers when >5 seconds of audio appears to be missing or over provided. Hopefully this will make the warning less annoying for those that are using audio sources with high and/or variable latencies. A status bar message is still posted for any amount of audio input samples unaccounted for >1/5 second, this message appearing a lot should be considered as notification that there is a problem with the audio sub-system, system load is too high, or time synchronization is stepping the PC clock rather than adjusting the frequency to maintain monotonic clock ticks. --- Audio/AudioDevice.cpp | 1 - Audio/AudioDevice.hpp | 4 +- Audio/soundin.cpp | 32 +++--- Audio/soundin.h | 3 +- Audio/soundout.cpp | 54 +++++----- Audio/soundout.h | 9 +- CMakeLists.txt | 1 + Configuration.cpp | 185 +++++++++++++++++++++-------------- Configuration.hpp | 2 + Configuration.ui | 143 ++++++++++++++------------- Detector/Detector.cpp | 3 +- Modulator/Modulator.cpp | 2 - widgets/LazyFillComboBox.cpp | 3 + widgets/LazyFillComboBox.hpp | 40 ++++++++ widgets/mainwindow.cpp | 8 +- 15 files changed, 291 insertions(+), 199 deletions(-) create mode 100644 widgets/LazyFillComboBox.cpp create mode 100644 widgets/LazyFillComboBox.hpp diff --git a/Audio/AudioDevice.cpp b/Audio/AudioDevice.cpp index 2b8525826..16fec3148 100644 --- a/Audio/AudioDevice.cpp +++ b/Audio/AudioDevice.cpp @@ -7,4 +7,3 @@ bool AudioDevice::initialize (OpenMode mode, Channel channel) // open and ensure we are unbuffered if possible return QIODevice::open (mode | QIODevice::Unbuffered); } - diff --git a/Audio/AudioDevice.hpp b/Audio/AudioDevice.hpp index 3ab19f0f4..2d47af89b 100644 --- a/Audio/AudioDevice.hpp +++ b/Audio/AudioDevice.hpp @@ -33,8 +33,8 @@ public: Channel channel () const {return m_channel;} protected: - AudioDevice (QObject * parent = 0) - : QIODevice (parent) + AudioDevice (QObject * parent = nullptr) + : QIODevice {parent} { } diff --git a/Audio/soundin.cpp b/Audio/soundin.cpp index 7dc940406..00129311a 100644 --- a/Audio/soundin.cpp +++ b/Audio/soundin.cpp @@ -10,11 +10,9 @@ #include "moc_soundin.cpp" -bool SoundInput::audioError () const +bool SoundInput::checkStream () { - bool result (true); - - Q_ASSERT_X (m_stream, "SoundInput", "programming error"); + bool result (false); if (m_stream) { switch (m_stream->error ()) @@ -36,9 +34,13 @@ bool SoundInput::audioError () const break; case QAudio::NoError: - result = false; + result = true; break; } + if (!result) + { + stop (); + } } return result; } @@ -74,12 +76,13 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi // qDebug () << "Selected audio input format:" << format; m_stream.reset (new QAudioInput {device, format}); - if (audioError ()) + if (!checkStream ()) { return; } connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged); + connect (m_stream.data(), &QAudioInput::notify, [this] () {checkStream ();}); //qDebug () << "SoundIn default buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize (); // the Windows MME version of QAudioInput uses 1/5 of the buffer @@ -89,10 +92,10 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi #else Q_UNUSED (framesPerBuffer); #endif - if (sink->initialize (QIODevice::WriteOnly, channel)) + if (m_sink->initialize (QIODevice::WriteOnly, channel)) { m_stream->start (sink); - audioError (); + checkStream (); cummulative_lost_usec_ = -1; //qDebug () << "SoundIn selected buffer size (bytes):" << m_stream->bufferSize () << "peirod size:" << m_stream->periodSize (); } @@ -107,7 +110,7 @@ void SoundInput::suspend () if (m_stream) { m_stream->suspend (); - audioError (); + checkStream (); } } @@ -122,14 +125,12 @@ void SoundInput::resume () if (m_stream) { m_stream->resume (); - audioError (); + checkStream (); } } void SoundInput::handleStateChanged (QAudio::State newState) { - //qDebug () << "SoundInput::handleStateChanged: newState:" << newState; - switch (newState) { case QAudio::IdleState: @@ -152,7 +153,7 @@ void SoundInput::handleStateChanged (QAudio::State newState) #endif case QAudio::StoppedState: - if (audioError ()) + if (!checkStream ()) { Q_EMIT status (tr ("Error")); } @@ -193,11 +194,6 @@ void SoundInput::stop() m_stream->stop (); } m_stream.reset (); - - if (m_sink) - { - m_sink->close (); - } } SoundInput::~SoundInput () diff --git a/Audio/soundin.h b/Audio/soundin.h index a126fbbd1..c35b3d7d8 100644 --- a/Audio/soundin.h +++ b/Audio/soundin.h @@ -24,7 +24,6 @@ class SoundInput public: SoundInput (QObject * parent = nullptr) : QObject {parent} - , m_sink {nullptr} , cummulative_lost_usec_ {std::numeric_limits::min ()} { } @@ -47,7 +46,7 @@ private: // used internally Q_SLOT void handleStateChanged (QAudio::State); - bool audioError () const; + bool checkStream (); QScopedPointer m_stream; QPointer m_sink; diff --git a/Audio/soundout.cpp b/Audio/soundout.cpp index 40eff6012..5e89de147 100644 --- a/Audio/soundout.cpp +++ b/Audio/soundout.cpp @@ -7,11 +7,13 @@ #include #include +#include "Audio/AudioDevice.hpp" + #include "moc_soundout.cpp" -bool SoundOutput::audioError () const +bool SoundOutput::checkStream () const { - bool result (true); + bool result {false}; Q_ASSERT_X (m_stream, "SoundOutput", "programming error"); if (m_stream) { @@ -34,7 +36,7 @@ bool SoundOutput::audioError () const break; case QAudio::NoError: - result = false; + result = true; break; } } @@ -43,15 +45,19 @@ bool SoundOutput::audioError () const void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered) { - if (!device.isNull ()) + Q_ASSERT (0 < channels && channels < 3); + m_device = device; + m_channels = channels; + m_framesBuffered = frames_buffered; +} + +void SoundOutput::restart (AudioDevice * source) +{ + if (!m_device.isNull ()) { - Q_ASSERT (0 < channels && channels < 3); - - m_framesBuffered = frames_buffered; - - QAudioFormat format (device.preferredFormat ()); + QAudioFormat format (m_device.preferredFormat ()); // qDebug () << "Preferred audio output format:" << format; - format.setChannelCount (channels); + format.setChannelCount (m_channels); format.setCodec ("audio/pcm"); format.setSampleRate (48000); format.setSampleType (QAudioFormat::SignedInt); @@ -61,29 +67,25 @@ void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, { Q_EMIT error (tr ("Requested output audio format is not valid.")); } - else if (!device.isFormatSupported (format)) + else if (!m_device.isFormatSupported (format)) { Q_EMIT error (tr ("Requested output audio format is not supported on device.")); } else { // qDebug () << "Selected audio output format:" << format; - - m_stream.reset (new QAudioOutput (device, format)); - audioError (); + m_stream.reset (new QAudioOutput (m_device, format)); + checkStream (); m_stream->setVolume (m_volume); - m_stream->setNotifyInterval(100); + m_stream->setNotifyInterval(1000); error_ = false; connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged); + connect (m_stream.data(), &QAudioOutput::notify, [this] () {checkStream ();}); // qDebug() << "A" << m_volume << m_stream->notifyInterval(); } } -} - -void SoundOutput::restart (QIODevice * source) -{ if (!m_stream) { if (!error_) @@ -109,6 +111,7 @@ void SoundOutput::restart (QIODevice * source) #endif } m_stream->setCategory ("production"); + m_source = source; m_stream->start (source); // qDebug () << "SoundOut selected buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize (); } @@ -118,7 +121,7 @@ void SoundOutput::suspend () if (m_stream && QAudio::ActiveState == m_stream->state ()) { m_stream->suspend (); - audioError (); + checkStream (); } } @@ -127,7 +130,7 @@ void SoundOutput::resume () if (m_stream && QAudio::SuspendedState == m_stream->state ()) { m_stream->resume (); - audioError (); + checkStream (); } } @@ -136,7 +139,7 @@ void SoundOutput::reset () if (m_stream) { m_stream->reset (); - audioError (); + checkStream (); } } @@ -144,9 +147,10 @@ void SoundOutput::stop () { if (m_stream) { + m_stream->reset (); m_stream->stop (); - audioError (); } + m_stream.reset (); } qreal SoundOutput::attenuation () const @@ -176,8 +180,6 @@ void SoundOutput::resetAttenuation () void SoundOutput::handleStateChanged (QAudio::State newState) { - // qDebug () << "SoundOutput::handleStateChanged: newState:" << newState; - switch (newState) { case QAudio::IdleState: @@ -199,7 +201,7 @@ void SoundOutput::handleStateChanged (QAudio::State newState) #endif case QAudio::StoppedState: - if (audioError ()) + if (!checkStream ()) { Q_EMIT status (tr ("Error")); } diff --git a/Audio/soundout.h b/Audio/soundout.h index c46e1563f..95efaeb15 100644 --- a/Audio/soundout.h +++ b/Audio/soundout.h @@ -6,7 +6,9 @@ #include #include #include +#include +class AudioDevice; class QAudioDeviceInfo; // An instance of this sends audio data to a specified soundcard. @@ -28,7 +30,7 @@ public: public Q_SLOTS: void setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered = 0); - void restart (QIODevice *); + void restart (AudioDevice *); void suspend (); void resume (); void reset (); @@ -41,13 +43,16 @@ Q_SIGNALS: void status (QString message) const; private: - bool audioError () const; + bool checkStream () const; private Q_SLOTS: void handleStateChanged (QAudio::State); private: + QAudioDeviceInfo m_device; + unsigned m_channels; QScopedPointer m_stream; + QPointer m_source; int m_framesBuffered; qreal m_volume; bool error_; diff --git a/CMakeLists.txt b/CMakeLists.txt index a2a31b388..f24abbbeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,6 +293,7 @@ set (wsjt_qt_CXXSRCS logbook/WorkedBefore.cpp logbook/Multiplier.cpp Network/NetworkAccessManager.cpp + widgets/LazyFillComboBox.cpp ) set (wsjt_qtmm_CXXSRCS diff --git a/Configuration.cpp b/Configuration.cpp index 91f9b1926..65b510b8e 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -188,6 +188,7 @@ #include "Network/LotWUsers.hpp" #include "models/DecodeHighlightingModel.hpp" #include "logbook/logbook.h" +#include "widgets/LazyFillComboBox.hpp" #include "ui_Configuration.h" #include "moc_Configuration.cpp" @@ -432,7 +433,6 @@ private: void read_settings (); void write_settings (); - Q_SLOT void lazy_models_load (int); void find_audio_devices (); QAudioDeviceInfo find_audio_device (QAudio::Mode, QComboBox *, QString const& device_name); void load_audio_devices (QAudio::Mode, QComboBox *, QAudioDeviceInfo *); @@ -653,9 +653,13 @@ private: bool pwrBandTuneMemory_; QAudioDeviceInfo audio_input_device_; + QAudioDeviceInfo next_audio_input_device_; AudioDevice::Channel audio_input_channel_; + AudioDevice::Channel next_audio_input_channel_; QAudioDeviceInfo audio_output_device_; + QAudioDeviceInfo next_audio_output_device_; AudioDevice::Channel audio_output_channel_; + AudioDevice::Channel next_audio_output_channel_; friend class Configuration; }; @@ -856,6 +860,16 @@ void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_s } } +void Configuration::invalidate_audio_input_device (QString /* error */) +{ + m_->audio_input_device_ = QAudioDeviceInfo {}; +} + +void Configuration::invalidate_audio_output_device (QString /* error */) +{ + m_->audio_output_device_ = QAudioDeviceInfo {}; +} + bool Configuration::valid_n1mm_info () const { // do very rudimentary checking on the n1mm server name and port number. @@ -1029,6 +1043,17 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network // this must be done after the default paths above are set read_settings (); + connect (ui_->sound_input_combo_box, &LazyFillComboBox::about_to_show_popup, [this] () { + load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &next_audio_input_device_); + update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false); + ui_->sound_input_channel_combo_box->setCurrentIndex (next_audio_input_channel_); + }); + connect (ui_->sound_output_combo_box, &LazyFillComboBox::about_to_show_popup, [this] () { + load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &next_audio_output_device_); + update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true); + ui_->sound_output_channel_combo_box->setCurrentIndex (next_audio_output_channel_); + }); + // set up LoTW users CSV file fetching connect (&lotw_users_, &LotWUsers::load_finished, [this] () { ui_->LotW_CSV_fetch_push_button->setEnabled (true); @@ -1102,7 +1127,6 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network // // setup hooks to keep audio channels aligned with devices // - connect (ui_->configuration_tabs, &QTabWidget::currentChanged, this, &Configuration::impl::lazy_models_load); { using namespace std; using namespace std::placeholders; @@ -1199,6 +1223,11 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network enumerate_rigs (); initialize_models (); + audio_input_device_ = next_audio_input_device_; + audio_input_channel_ = next_audio_input_channel_; + audio_output_device_ = next_audio_output_device_; + audio_output_channel_ = next_audio_output_channel_; + transceiver_thread_ = new QThread {this}; transceiver_thread_->start (); } @@ -1210,31 +1239,14 @@ Configuration::impl::~impl () write_settings (); } -void Configuration::impl::lazy_models_load (int current_tab_index) -{ - switch (current_tab_index) - { - case 2: // Audio - // - // load combo boxes with audio setup choices - // - load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_); - load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &audio_output_device_); - - update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false); - update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true); - - ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_); - ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_); - break; - - default: - break; - } -} - void Configuration::impl::initialize_models () { + next_audio_input_device_ = audio_input_device_; + next_audio_input_channel_ = audio_input_channel_; + next_audio_output_device_ = audio_output_device_; + next_audio_output_channel_ = audio_output_channel_; + restart_sound_input_device_ = false; + restart_sound_output_device_ = false; { SettingsGroup g {settings_, "Configuration"}; find_audio_devices (); @@ -1413,8 +1425,6 @@ void Configuration::impl::read_settings () save_directory_.setPath (settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString ()); azel_directory_.setPath (settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ()); - find_audio_devices (); - type_2_msg_gen_ = settings_->value ("Type2MsgGen", QVariant::fromValue (Configuration::type_2_msg_3_full)).value (); monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool (); @@ -1522,24 +1532,24 @@ void Configuration::impl::find_audio_devices () // retrieve audio input device // auto saved_name = settings_->value ("SoundInName").toString (); - if (audio_input_device_.deviceName () != saved_name) + if (next_audio_input_device_.deviceName () != saved_name || next_audio_input_device_.isNull ()) { - audio_input_device_ = find_audio_device (QAudio::AudioInput, ui_->sound_input_combo_box, saved_name); - audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ()); + next_audio_input_device_ = find_audio_device (QAudio::AudioInput, ui_->sound_input_combo_box, saved_name); + next_audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ()); update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false); - ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_); + ui_->sound_input_channel_combo_box->setCurrentIndex (next_audio_input_channel_); } // // retrieve audio output device // saved_name = settings_->value("SoundOutName").toString(); - if (audio_output_device_.deviceName () != saved_name) + if (next_audio_output_device_.deviceName () != saved_name || next_audio_output_device_.isNull ()) { - audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ()); - audio_output_device_ = find_audio_device (QAudio::AudioOutput, ui_->sound_output_combo_box, saved_name); + next_audio_output_device_ = find_audio_device (QAudio::AudioOutput, ui_->sound_output_combo_box, saved_name); + next_audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ()); update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true); - ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_); + ui_->sound_output_channel_combo_box->setCurrentIndex (next_audio_output_channel_); } } @@ -1562,10 +1572,16 @@ void Configuration::impl::write_settings () settings_->setValue ("PTTport", rig_params_.ptt_port); settings_->setValue ("SaveDir", save_directory_.absolutePath ()); settings_->setValue ("AzElDir", azel_directory_.absolutePath ()); - settings_->setValue ("SoundInName", audio_input_device_.deviceName ()); - settings_->setValue ("SoundOutName", audio_output_device_.deviceName ()); - settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_)); - settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_)); + if (!audio_input_device_.isNull ()) + { + settings_->setValue ("SoundInName", audio_input_device_.deviceName ()); + settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_)); + } + if (!audio_output_device_.isNull ()) + { + settings_->setValue ("SoundOutName", audio_output_device_.deviceName ()); + settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_)); + } settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_)); settings_->setValue ("MonitorOFF", monitor_off_at_startup_); settings_->setValue ("MonitorLastUsed", monitor_last_used_); @@ -1770,7 +1786,7 @@ void Configuration::impl::set_rig_invariants () bool Configuration::impl::validate () { if (ui_->sound_input_combo_box->currentIndex () < 0 - && audio_input_device_.isNull ()) + && next_audio_input_device_.isNull ()) { find_tab (ui_->sound_input_combo_box); MessageBox::critical_message (this, tr ("Invalid audio input device")); @@ -1778,7 +1794,7 @@ bool Configuration::impl::validate () } if (ui_->sound_input_channel_combo_box->currentIndex () < 0 - && audio_input_device_.isNull ()) + && next_audio_input_device_.isNull ()) { find_tab (ui_->sound_input_combo_box); MessageBox::critical_message (this, tr ("Invalid audio input device")); @@ -1786,7 +1802,7 @@ bool Configuration::impl::validate () } if (ui_->sound_output_combo_box->currentIndex () < 0 - && audio_output_device_.isNull ()) + && next_audio_output_device_.isNull ()) { find_tab (ui_->sound_output_combo_box); MessageBox::information_message (this, tr ("Invalid audio output device")); @@ -1842,7 +1858,6 @@ int Configuration::impl::exec () rig_changed_ = false; initialize_models (); - lazy_models_load (ui_->configuration_tabs->currentIndex ()); return QDialog::exec(); } @@ -1941,39 +1956,60 @@ void Configuration::impl::accept () // related configuration parameters rig_is_dummy_ = TransceiverFactory::basic_transceiver_name_ == rig_params_.rig_name; - // Check to see whether SoundInThread must be restarted, - // and save user parameters. { auto const& selected_device = ui_->sound_input_combo_box->currentData ().value ().first; - if (selected_device != audio_input_device_) + if (selected_device != next_audio_input_device_) { - audio_input_device_ = selected_device; - restart_sound_input_device_ = true; + next_audio_input_device_ = selected_device; } } { auto const& selected_device = ui_->sound_output_combo_box->currentData ().value ().first; - if (selected_device != audio_output_device_) + if (selected_device != next_audio_output_device_) { - audio_output_device_ = selected_device; - restart_sound_output_device_ = true; + next_audio_output_device_ = selected_device; } } - if (audio_input_channel_ != static_cast (ui_->sound_input_channel_combo_box->currentIndex ())) + if (next_audio_input_channel_ != static_cast (ui_->sound_input_channel_combo_box->currentIndex ())) { - audio_input_channel_ = static_cast (ui_->sound_input_channel_combo_box->currentIndex ()); + next_audio_input_channel_ = static_cast (ui_->sound_input_channel_combo_box->currentIndex ()); + } + Q_ASSERT (next_audio_input_channel_ <= AudioDevice::Right); + + if (next_audio_output_channel_ != static_cast (ui_->sound_output_channel_combo_box->currentIndex ())) + { + next_audio_output_channel_ = static_cast (ui_->sound_output_channel_combo_box->currentIndex ()); + } + Q_ASSERT (next_audio_output_channel_ <= AudioDevice::Both); + + if (audio_input_device_ != next_audio_input_device_ || next_audio_input_device_.isNull ()) + { + audio_input_device_ = next_audio_input_device_; restart_sound_input_device_ = true; } - Q_ASSERT (audio_input_channel_ <= AudioDevice::Right); - - if (audio_output_channel_ != static_cast (ui_->sound_output_channel_combo_box->currentIndex ())) + if (audio_input_channel_ != next_audio_input_channel_) { - audio_output_channel_ = static_cast (ui_->sound_output_channel_combo_box->currentIndex ()); + audio_input_channel_ = next_audio_input_channel_; + restart_sound_input_device_ = true; + } + if (audio_output_device_ != next_audio_output_device_ || next_audio_output_device_.isNull ()) + { + audio_output_device_ = next_audio_output_device_; restart_sound_output_device_ = true; } - Q_ASSERT (audio_output_channel_ <= AudioDevice::Both); + if (audio_output_channel_ != next_audio_output_channel_) + { + audio_output_channel_ = next_audio_output_channel_; + restart_sound_output_device_ = true; + } + // qDebug () << "Configure::accept: audio i/p:" << audio_input_device_.deviceName () + // << "chan:" << audio_input_channel_ + // << "o/p:" << audio_output_device_.deviceName () + // << "chan:" << audio_output_channel_ + // << "reset i/p:" << restart_sound_input_device_ + // << "reset o/p:" << restart_sound_output_device_; my_callsign_ = ui_->callsign_line_edit->text (); my_grid_ = ui_->grid_line_edit->text (); @@ -2112,6 +2148,13 @@ void Configuration::impl::reject () } } + // qDebug () << "Configure::reject: audio i/p:" << audio_input_device_.deviceName () + // << "chan:" << audio_input_channel_ + // << "o/p:" << audio_output_device_.deviceName () + // << "chan:" << audio_output_channel_ + // << "reset i/p:" << restart_sound_input_device_ + // << "reset o/p:" << restart_sound_output_device_; + QDialog::reject (); } @@ -2772,27 +2815,25 @@ QAudioDeviceInfo Configuration::impl::find_audio_device (QAudio::Mode mode, QCom if (device_name.size ()) { - combo_box->clear (); - - int current_index = -1; + Q_EMIT self_->enumerating_audio_devices (); auto const& devices = QAudioDeviceInfo::availableDevices (mode); Q_FOREACH (auto const& p, devices) { - - // convert supported channel counts into something we can store in the item model - QList channel_counts; - auto scc = p.supportedChannelCounts (); - copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts)); - - combo_box->addItem (p.deviceName (), QVariant::fromValue (audio_info_type {p, channel_counts})); + qDebug () << "Configuration::impl::find_audio_device: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes (); if (p.deviceName () == device_name) { - current_index = combo_box->count () - 1; - combo_box->setCurrentIndex (current_index); + // convert supported channel counts into something we can store in the item model + QList channel_counts; + auto scc = p.supportedChannelCounts (); + copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts)); + combo_box->insertItem (0, device_name, QVariant::fromValue (audio_info_type {p, channel_counts})); + combo_box->setCurrentIndex (0); return p; } } - combo_box->setCurrentIndex (current_index); + // insert a place holder for the not found device + combo_box->insertItem (0, device_name + " (" + tr ("Not found", "audio device missing") + ")", QVariant::fromValue (audio_info_type {})); + combo_box->setCurrentIndex (0); } return {}; } @@ -2811,7 +2852,7 @@ void Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * com auto const& devices = QAudioDeviceInfo::availableDevices (mode); Q_FOREACH (auto const& p, devices) { - // qDebug () << "Audio device: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes (); + // qDebug () << "Configuration::impl::load_audio_devices: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes (); // convert supported channel counts into something we can store in the item model QList channel_counts; diff --git a/Configuration.hpp b/Configuration.hpp index 45fafe59b..8594a4a6f 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -260,6 +260,8 @@ public: // i.e. the transceiver is ready for use. Q_SLOT void sync_transceiver (bool force_signal = false, bool enforce_mode_and_split = false); + Q_SLOT void invalidate_audio_input_device (QString error); + Q_SLOT void invalidate_audio_output_device (QString error); // // These signals indicate a font has been selected and accepted for diff --git a/Configuration.ui b/Configuration.ui index 4c8035754..d22032d53 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -7,7 +7,7 @@ 0 0 554 - 557 + 556 @@ -1364,71 +1364,8 @@ radio interface behave as expected. Soundcard - - - - Ou&tput: - - - sound_output_combo_box - - - - - - - &Input: - - - sound_input_combo_box - - - - - - - Select the audio channel used for transmission. -Unless you have multiple radios connected on different -channels; then you will usually want to select mono or -both here. - - - - Mono - - - - - Left - - - - - Right - - - - - Both - - - - - - - - - 1 - 0 - - - - Select the audio CODEC to use for receiving. - - - - + 1 @@ -1471,6 +1408,69 @@ transmitting periods. + + + + + 1 + 0 + + + + Select the audio CODEC to use for receiving. + + + + + + + Ou&tput: + + + sound_output_combo_box + + + + + + + Select the audio channel used for transmission. +Unless you have multiple radios connected on different +channels; then you will usually want to select mono or +both here. + + + + Mono + + + + + Left + + + + + Right + + + + + Both + + + + + + + + &Input: + + + sound_input_combo_box + + + @@ -2997,6 +2997,11 @@ Right click for insert and delete options. QListView
widgets/DecodeHighlightingListView.hpp
+ + LazyFillComboBox + QComboBox +
widgets/LazyFillComboBox.hpp
+
configuration_tabs @@ -3187,13 +3192,13 @@ Right click for insert and delete options. + + + - - - - + diff --git a/Detector/Detector.cpp b/Detector/Detector.cpp index d70dd42ff..164db2ab2 100644 --- a/Detector/Detector.cpp +++ b/Detector/Detector.cpp @@ -36,7 +36,7 @@ void Detector::setBlockSize (unsigned n) bool Detector::reset () { clear (); - // don't call base call reset because it calls seek(0) which causes + // don't call base class reset because it calls seek(0) which causes // a warning return isOpen (); } @@ -56,7 +56,6 @@ void Detector::clear () qint64 Detector::writeData (char const * data, qint64 maxSize) { - //qDebug () << "Detector::writeData: size:" << maxSize; static unsigned mstr0=999999; qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time diff --git a/Modulator/Modulator.cpp b/Modulator/Modulator.cpp index df365c507..96963029f 100644 --- a/Modulator/Modulator.cpp +++ b/Modulator/Modulator.cpp @@ -149,8 +149,6 @@ void Modulator::close () qint64 Modulator::readData (char * data, qint64 maxSize) { - // qDebug () << "readData: maxSize:" << maxSize; - double toneFrequency=1500.0; if(m_nsps==6) { toneFrequency=1000.0; diff --git a/widgets/LazyFillComboBox.cpp b/widgets/LazyFillComboBox.cpp new file mode 100644 index 000000000..08968f357 --- /dev/null +++ b/widgets/LazyFillComboBox.cpp @@ -0,0 +1,3 @@ +#include "LazyFillComboBox.hpp" + +#include "moc_LazyFillComboBox.cpp" diff --git a/widgets/LazyFillComboBox.hpp b/widgets/LazyFillComboBox.hpp new file mode 100644 index 000000000..7d9052673 --- /dev/null +++ b/widgets/LazyFillComboBox.hpp @@ -0,0 +1,40 @@ +#ifndef LAZY_FILL_COMBO_BOX_HPP__ +#define LAZY_FILL_COMBO_BOX_HPP__ + +#include + +class QWidget; + +// +// Class LazyFillComboBox +// +// QComboBox derivative that signals show and hide of the pop up list. +// +class LazyFillComboBox final + : public QComboBox +{ + Q_OBJECT + +public: + Q_SIGNAL void about_to_show_popup (); + Q_SIGNAL void popup_hidden (); + + explicit LazyFillComboBox (QWidget * parent = nullptr) + : QComboBox {parent} + { + } + + void showPopup () override + { + Q_EMIT about_to_show_popup (); + QComboBox::showPopup (); + } + + void hidePopup () override + { + QComboBox::hidePopup (); + Q_EMIT popup_hidden (); + } +}; + +#endif diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 8b27440c5..d8461bd67 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -454,6 +454,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, // hook up sound output stream slots & signals and disposal connect (this, &MainWindow::initializeAudioOutputStream, m_soundOutput, &SoundOutput::setFormat); connect (m_soundOutput, &SoundOutput::error, this, &MainWindow::showSoundOutError); + connect (m_soundOutput, &SoundOutput::error, &m_config, &Configuration::invalidate_audio_output_device); // connect (m_soundOutput, &SoundOutput::status, this, &MainWindow::showStatusMessage); connect (this, &MainWindow::outAttenuationChanged, m_soundOutput, &SoundOutput::setAttenuation); connect (&m_audioThread, &QThread::finished, m_soundOutput, &QObject::deleteLater); @@ -472,13 +473,14 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, connect (this, &MainWindow::reset_audio_input_stream, m_soundInput, &SoundInput::reset); connect (this, &MainWindow::finished, m_soundInput, &SoundInput::stop); connect(m_soundInput, &SoundInput::error, this, &MainWindow::showSoundInError); + connect(m_soundInput, &SoundInput::error, &m_config, &Configuration::invalidate_audio_input_device); // connect(m_soundInput, &SoundInput::status, this, &MainWindow::showStatusMessage); connect (m_soundInput, &SoundInput::dropped_frames, this, [this] (qint32 dropped_frames, qint64 usec) { if (dropped_frames > 48000 / 5) // 1/5 second { showStatusMessage (tr ("%1 (%2 sec) audio frames dropped").arg (dropped_frames).arg (usec / 1.e6, 5, 'f', 3)); } - if (dropped_frames > 48000) // 1 second + if (dropped_frames > 5 * 48000) // seconds { auto period = qt_truncate_date_time_to (QDateTime::currentDateTimeUtc ().addMSecs (-m_TRperiod / 2.), m_TRperiod * 1e3); MessageBox::warning_message (this @@ -1824,14 +1826,14 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog m_psk_Reporter.sendReport (true); } - if(m_config.restart_audio_input ()) { + if(m_config.restart_audio_input () && !m_config.audio_input_device ().isNull ()) { Q_EMIT startAudioInputStream (m_config.audio_input_device () , rx_chunk_size * m_downSampleFactor , m_detector, m_downSampleFactor , m_config.audio_input_channel ()); } - if(m_config.restart_audio_output ()) { + if(m_config.restart_audio_output () && !m_config.audio_output_device ().isNull ()) { Q_EMIT initializeAudioOutputStream (m_config.audio_output_device () , AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2 , tx_audio_buffer_size);