diff --git a/CMakeLists.txt b/CMakeLists.txt index 788ee435c..65dcb62d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,6 +274,7 @@ set (wsjtx_CXXSRCS widgets/about.cpp widgets/astro.cpp widgets/messageaveraging.cpp + widgets/activeStations.cpp widgets/colorhighlighting.cpp WSPR/WsprTxScheduler.cpp widgets/mainwindow.cpp @@ -653,6 +654,7 @@ set (wsjtx_UISRCS widgets/echograph.ui widgets/fastgraph.ui widgets/messageaveraging.ui + widgets/activeStations.ui widgets/widegraph.ui widgets/logqso.ui Configuration.ui diff --git a/Configuration.cpp b/Configuration.cpp index 661a42d6e..01020027a 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -646,6 +646,7 @@ private: bool TX_messages_; bool enable_VHF_features_; bool decode_at_52s_; + bool Tune_watchdog_disabled_; bool single_decode_; bool twoPass_; bool bSpecialOp_; @@ -755,6 +756,7 @@ int Configuration::watchdog () const {return m_->watchdog_;} bool Configuration::TX_messages () const {return m_->TX_messages_;} bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features_;} bool Configuration::decode_at_52s () const {return m_->decode_at_52s_;} +bool Configuration::Tune_watchdog_disabled () const {return m_->Tune_watchdog_disabled_;} bool Configuration::single_decode () const {return m_->single_decode_;} bool Configuration::twoPass() const {return m_->twoPass_;} bool Configuration::x2ToneSpacing() const {return m_->x2ToneSpacing_;} @@ -903,7 +905,7 @@ QString Configuration::Field_Day_Exchange() const { return m_->FD_exchange_; } - +/* void Configuration::setEU_VHF_Contest() { m_->bSpecialOp_=true; @@ -912,6 +914,7 @@ void Configuration::setEU_VHF_Contest() m_->SelectedActivity_ = static_cast (SpecialOperatingActivity::EU_VHF); m_->write_settings(); } +*/ QString Configuration::RTTY_Exchange() const { @@ -1157,6 +1160,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network ui_->special_op_activity_button_group->setId (ui_->rbField_Day, static_cast (SpecialOperatingActivity::FIELD_DAY)); ui_->special_op_activity_button_group->setId (ui_->rbRTTY_Roundup, static_cast (SpecialOperatingActivity::RTTY)); ui_->special_op_activity_button_group->setId (ui_->rbWW_DIGI, static_cast (SpecialOperatingActivity::WW_DIGI)); + ui_->special_op_activity_button_group->setId (ui_->rbARRL_Digi, static_cast (SpecialOperatingActivity::ARRL_DIGI)); ui_->special_op_activity_button_group->setId (ui_->rbFox, static_cast (SpecialOperatingActivity::FOX)); ui_->special_op_activity_button_group->setId (ui_->rbHound, static_cast (SpecialOperatingActivity::HOUND)); @@ -1355,6 +1359,7 @@ void Configuration::impl::initialize_models () ui_->TX_messages_check_box->setChecked (TX_messages_); ui_->enable_VHF_features_check_box->setChecked(enable_VHF_features_); ui_->decode_at_52s_check_box->setChecked(decode_at_52s_); + ui_->disable_Tune_watchdog_check_box->setChecked(Tune_watchdog_disabled_); ui_->single_decode_check_box->setChecked(single_decode_); ui_->cbTwoPass->setChecked(twoPass_); ui_->gbSpecialOpActivity->setChecked(bSpecialOp_); @@ -1572,6 +1577,7 @@ void Configuration::impl::read_settings () TX_messages_ = settings_->value ("Tx2QSO", true).toBool (); enable_VHF_features_ = settings_->value("VHFUHF",false).toBool (); decode_at_52s_ = settings_->value("Decode52",false).toBool (); + Tune_watchdog_disabled_ = settings_->value("TuneWatchdogDisabled",false).toBool (); single_decode_ = settings_->value("SingleDecode",false).toBool (); twoPass_ = settings_->value("TwoPass",true).toBool (); bSpecialOp_ = settings_->value("SpecialOpActivity",false).toBool (); @@ -1708,6 +1714,7 @@ void Configuration::impl::write_settings () settings_->setValue ("SplitMode", QVariant::fromValue (rig_params_.split_mode)); settings_->setValue ("VHFUHF", enable_VHF_features_); settings_->setValue ("Decode52", decode_at_52s_); + settings_->setValue ("TuneWatchdogDisabled", Tune_watchdog_disabled_); settings_->setValue ("SingleDecode", single_decode_); settings_->setValue ("TwoPass", twoPass_); settings_->setValue ("SelectedActivity", SelectedActivity_); @@ -2138,6 +2145,7 @@ void Configuration::impl::accept () azel_directory_.setPath (ui_->azel_path_display_label->text ()); enable_VHF_features_ = ui_->enable_VHF_features_check_box->isChecked (); decode_at_52s_ = ui_->decode_at_52s_check_box->isChecked (); + Tune_watchdog_disabled_ = ui_->disable_Tune_watchdog_check_box->isChecked (); single_decode_ = ui_->single_decode_check_box->isChecked (); twoPass_ = ui_->cbTwoPass->isChecked (); bSpecialOp_ = ui_->gbSpecialOpActivity->isChecked (); @@ -2227,7 +2235,6 @@ void Configuration::impl::accept () clear_DXcall_ = ui_->cbClearDXcall->isChecked(); highlight_DXgrid_ = ui_->cbHighlightDXgrid->isChecked(); clear_DXgrid_ = ui_->cbClearDXgrid->isChecked(); - write_settings (); // make visible to all } diff --git a/Configuration.hpp b/Configuration.hpp index c4cf068ec..bd31d8695 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -134,6 +134,7 @@ public: bool split_mode () const; bool enable_VHF_features () const; bool decode_at_52s () const; + bool Tune_watchdog_disabled () const; bool single_decode () const; bool twoPass() const; bool bFox() const; @@ -190,7 +191,7 @@ public: bool highlight_DXgrid () const; bool clear_DXgrid () const; - enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, FOX, HOUND}; + enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, ARRL_DIGI, FOX, HOUND}; SpecialOperatingActivity special_op_id () const; struct CalibrationParams diff --git a/Configuration.ui b/Configuration.ui index c538b0be6..ad62f515e 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -517,6 +517,16 @@ quiet period when decoding is done. + + + + <html><head/><body><p>Disable the Tune watchdog.</p></body></html> + + + Disable Tune watchdog + + + @@ -2518,74 +2528,6 @@ Right click for insert and delete options. Advanced - - - - <html><head/><body><p>User-selectable parameters for JT65 VHF/UHF/Microwave decoding.</p></body></html> - - - JT65 VHF/UHF/Microwave decoding parameters - - - - - - Random erasure patterns: - - - sbNtrials - - - - - - - <html><head/><body><p>Maximum number of erasure patterns for stochastic soft-decision Reed Solomon decoder is 10^(n/2).</p></body></html> - - - 0 - - - 12 - - - 6 - - - - - - - Aggressive decoding level: - - - sbAggressive - - - - - - - <html><head/><body><p>Higher levels will increase the probability of decoding, but will also increase probability of a false decode.</p></body></html> - - - 10 - - - - - - - Two-pass decoding - - - true - - - - - - @@ -2598,47 +2540,6 @@ Right click for insert and delete options. false - - - - <html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html> - - - Hound - - - Hound - - - true - - - special_op_activity_button_group - - - - - - - - 0 - 0 - - - - <html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html> - - - NA VHF Contest - - - NA VHF Contest - - - special_op_activity_button_group - - - @@ -2680,6 +2581,28 @@ Right click for insert and delete options. + + + + + 0 + 0 + + + + <html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html> + + + NA VHF Contest + + + NA VHF + + + special_op_activity_button_group + + + @@ -2693,74 +2616,24 @@ Right click for insert and delete options. - - - - - - <html><head/><body><p>ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html> - - - R T T Y Roundup - - - RTTY Roundup messages - - - special_op_activity_button_group - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - RTTY Roundup exchange - - - RTTY RU Exch: - - - RTTY_Exchange - - - - - - - - 70 - 0 - - - - <html><head/><body><p>ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html> - - - NJ - - - Qt::AlignCenter - - - - - - + + + + <html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html> + + + Hound + + + Hound + + + true + + + special_op_activity_button_group + + @@ -2853,6 +2726,88 @@ Right click for insert and delete options. + + + + + + <html><head/><body><p>ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html> + + + R T T Y Roundup + + + RTTY Roundup messages + + + special_op_activity_button_group + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + RTTY Roundup exchange + + + RTTY RU Exch: + + + RTTY_Exchange + + + + + + + + 70 + 0 + + + + <html><head/><body><p>ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html> + + + NJ + + + Qt::AlignCenter + + + + + + + + + + + <html><head/><body><p>ARRL International Digital Contest</p></body></html> + + + ARRL Digi Contest + + + special_op_activity_button_group + + + @@ -3028,6 +2983,74 @@ Right click for insert and delete options. + + + + <html><head/><body><p>User-selectable parameters for JT65 VHF/UHF/Microwave decoding.</p></body></html> + + + JT65 VHF/UHF/Microwave decoding parameters + + + + + + Random erasure patterns: + + + sbNtrials + + + + + + + <html><head/><body><p>Maximum number of erasure patterns for stochastic soft-decision Reed Solomon decoder is 10^(n/2).</p></body></html> + + + 0 + + + 12 + + + 6 + + + + + + + Aggressive decoding level: + + + sbAggressive + + + + + + + <html><head/><body><p>Higher levels will increase the probability of decoding, but will also increase probability of a false decode.</p></body></html> + + + 10 + + + + + + + Two-pass decoding + + + true + + + + + + @@ -3268,13 +3291,13 @@ Right click for insert and delete options. + + + + + - - - - - diff --git a/lib/ft8/ft8_a7.f90 b/lib/ft8/ft8_a7.f90 index 7306c8021..d32c96348 100644 --- a/lib/ft8/ft8_a7.f90 +++ b/lib/ft8/ft8_a7.f90 @@ -364,7 +364,7 @@ subroutine ft8_a7d(dd0,newdat,call_1,call_2,grid4,xdt,f1,xbase,nharderrors,dmin, dmin2=dmm(iloc(1)) xsnr=-24. arg=pbest/xbase/3.0e6-1.0 - if(arg.gt.0.0) xsnr=db(arg)-27.0 + if(arg.gt.0.0) xsnr=max(-24.0,db(arg)-27.0) ! write(41,3041) nharderrors,dmin,dmin2,dmin2/dmin,xsnr,trim(msgbest) !3041 format(i3,2f7.1,f7.2,f7.1,1x,a) if(dmin.gt.100.0 .or. dmin2/dmin.lt.1.3) nharderrors=-1 diff --git a/lib/qra/q65/q65.f90 b/lib/qra/q65/q65.f90 index 65683dd71..2133294ef 100644 --- a/lib/qra/q65/q65.f90 +++ b/lib/qra/q65/q65.f90 @@ -781,9 +781,8 @@ subroutine q65_snr(dat4,dtdec,f0dec,mode_q65,nused,snr2) sig_area=sum(spec(ia+nsum:ib-nsum)-1.0) w_equiv=sig_area/(smax-1.0) snr2=db(max(1.0,sig_area)) - db(2500.0/df) - if(nused.eq.2) snr2=snr2 - 1.5 - if(nused.eq.3) snr2=snr2 - 2.4 - if(nused.ge.4) snr2=snr2 - 3.0 +! NB: No adjustment to SNR is now made for nused>1, because that process did +! not seem to work as expected. return end subroutine q65_snr diff --git a/widgets/activeStations.cpp b/widgets/activeStations.cpp new file mode 100644 index 000000000..b5ecbf737 --- /dev/null +++ b/widgets/activeStations.cpp @@ -0,0 +1,125 @@ +#include "activeStations.h" + +#include +#include +#include +#include +#include + +#include "SettingsGroup.hpp" +#include "qt_helpers.hpp" +#include "ui_activeStations.h" + +#include "moc_activeStations.cpp" + +ActiveStations::ActiveStations(QSettings * settings, QFont const& font, QWidget *parent) : + QWidget(parent), + settings_ {settings}, + ui(new Ui::ActiveStations) +{ + ui->setupUi(this); + setWindowTitle (QApplication::applicationName () + " - " + tr ("Active Stations")); + ui->RecentStationsPlainTextEdit->setReadOnly (true); + changeFont (font); + read_settings (); + ui->header_label2->setText(" N Call Grid Az S/N Freq Tx Age Pts"); + connect(ui->RecentStationsPlainTextEdit, SIGNAL(selectionChanged()), this, SLOT(select())); + connect(ui->cbReadyOnly, SIGNAL(toggled(bool)), this, SLOT(on_cbReadyOnly_toggled(bool))); +} + +ActiveStations::~ActiveStations() +{ + write_settings (); +} + +void ActiveStations::changeFont (QFont const& font) +{ + ui->header_label2->setStyleSheet (font_as_stylesheet (font)); + ui->RecentStationsPlainTextEdit->setStyleSheet (font_as_stylesheet (font)); + updateGeometry (); +} + +void ActiveStations::read_settings () +{ + SettingsGroup group {settings_, "ActiveStations"}; + restoreGeometry (settings_->value ("window/geometry").toByteArray ()); + ui->sbMaxRecent->setValue(settings_->value("MaxRecent",10).toInt()); + ui->sbMaxAge->setValue(settings_->value("MaxAge",10).toInt()); + ui->cbReadyOnly->setChecked(settings_->value("ReadyOnly",false).toBool()); +} + +void ActiveStations::write_settings () +{ + SettingsGroup group {settings_, "ActiveStations"}; + settings_->setValue ("window/geometry", saveGeometry ()); + settings_->setValue("MaxRecent",ui->sbMaxRecent->value()); + settings_->setValue("MaxAge",ui->sbMaxAge->value()); + settings_->setValue("ReadyOnly",ui->cbReadyOnly->isChecked()); +} + +void ActiveStations::displayRecentStations(QString const& t) +{ + ui->RecentStationsPlainTextEdit->setPlainText(t); +} + +int ActiveStations::maxRecent() +{ + return ui->sbMaxRecent->value(); +} + +int ActiveStations::maxAge() +{ + return ui->sbMaxAge->value(); +} + +void ActiveStations::select() +{ + if(m_clickOK) { + qint64 msec=QDateTime::currentMSecsSinceEpoch(); + if((msec-m_msec0)<500) return; + m_msec0=msec; + int nline=ui->RecentStationsPlainTextEdit->textCursor().blockNumber(); + emit callSandP(nline); + } +} + +void ActiveStations::setClickOK(bool b) +{ + m_clickOK=b; +} + +void ActiveStations::erase() +{ + ui->RecentStationsPlainTextEdit->clear(); +} + +bool ActiveStations::readyOnly() +{ + return ui->cbReadyOnly->isChecked(); +} + +void ActiveStations::on_cbReadyOnly_toggled(bool b) +{ + m_bReadyOnly=b; + emit activeStationsDisplay(); +} + +void ActiveStations::setRate(int n) +{ + ui->rate->setText(QString::number(n)); +} + +void ActiveStations::setScore(int n) +{ + ui->score->setText(QLocale(QLocale::English).toString(n)); +} + +void ActiveStations::setBandChanges(int n) +{ + if(n >= 8) { + ui->bandChanges->setStyleSheet("QLineEdit{background: rgb(255, 64, 64)}"); + } else { + ui->bandChanges->setStyleSheet (""); + } + ui->bandChanges->setText(QString::number(n)); +} diff --git a/widgets/activeStations.h b/widgets/activeStations.h new file mode 100644 index 000000000..1897f08d9 --- /dev/null +++ b/widgets/activeStations.h @@ -0,0 +1,52 @@ +// -*- Mode: C++ -*- +#ifndef ARRL_DIGI_H_ +#define ARRL_DIGI_H_ + +#include + +class QSettings; +class QFont; + +namespace Ui { + class ActiveStations; +} + +class ActiveStations + : public QWidget +{ + Q_OBJECT + +public: + explicit ActiveStations(QSettings *, QFont const&, QWidget * parent = 0); + ~ActiveStations(); + void displayRecentStations(QString const&); + void changeFont (QFont const&); + int maxRecent(); + int maxAge(); + void setClickOK(bool b); + void erase(); + bool readyOnly(); + void setRate(int n); + void setBandChanges(int n); + void setScore(int n); + Q_SLOT void select(); + + bool m_clickOK=false; + bool m_bReadyOnly; + +signals: + void callSandP(int nline); + void activeStationsDisplay(); + +private: + void read_settings (); + void write_settings (); + Q_SLOT void on_cbReadyOnly_toggled(bool b); + + qint64 m_msec0=0; + QSettings * settings_; + + QScopedPointer ui; +}; + +#endif diff --git a/widgets/activeStations.ui b/widgets/activeStations.ui new file mode 100644 index 000000000..16f077687 --- /dev/null +++ b/widgets/activeStations.ui @@ -0,0 +1,193 @@ + + + ActiveStations + + + + 0 + 0 + 395 + 339 + + + + Message Averaging + + + + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + <html><head/><body><p>Set maximum number of displayed lines.</p></body></html> + + + Max N + + + 50 + + + 10 + + + + + + + + 16777215 + 16777215 + + + + <html><head/><body><p>Points logged during the past hour.</p></body></html> + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + <html><head/><body><p>Set maximum elapsed number of T/R sequences.</p></body></html> + + + Max Age + + + 0 + + + 10 + + + 4 + + + + + + + Score: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Rate: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p>Total score accumulated since most recent reset of Cabrillo log.</p></body></html> + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p>Check tis box to show only stations ready to be called.</p></body></html> + + + Ready only + + + + + + + Band Changes: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + <html><head/><body><p>Number of band changes during the past hour.</p></body></html> + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 0 + 1 + + + + <html><head/><body><p>Click on a line to call that station.</p></body></html> + + + + + + + Call Grid Age Points + + + + + + + + + + diff --git a/widgets/displaytext.cpp b/widgets/displaytext.cpp index c3e31f83c..65fc1d40b 100644 --- a/widgets/displaytext.cpp +++ b/widgets/displaytext.cpp @@ -277,6 +277,8 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons gridB4onBand=true; } + if(callB4onBand) m_points=0; + message = message.trimmed (); highlight_types types; @@ -372,11 +374,17 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons } m_CQPriority=DecodeHighlightingModel::highlight_name(top_highlight); + if(((m_points == 00) or (m_points == -1)) and m_bDisplayPoints) return message; return leftJustifyAppendage (message, extra); } -QString DisplayText::leftJustifyAppendage (QString message, QString const& appendage) const +QString DisplayText::leftJustifyAppendage (QString message, QString const& appendage0) const { + QString appendage=appendage0; + if(m_bDisplayPoints and (m_points>0)) { + appendage=" " + QString::number(m_points); + if(m_points<10) appendage=" " + appendage; + } if (appendage.size ()) { // allow for seconds @@ -398,8 +406,10 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con QString const& mode, bool displayDXCCEntity, LogBook const& logBook, QString const& currentBand, bool ppfx, bool bCQonly, - bool haveFSpread, float fSpread) + bool haveFSpread, float fSpread, bool bDisplayPoints, int points) { + m_points=points; + m_bDisplayPoints=bDisplayPoints; m_bPrincipalPrefix=ppfx; QColor bg; QColor fg; diff --git a/widgets/displaytext.h b/widgets/displaytext.h index 773901cea..5810972cd 100644 --- a/widgets/displaytext.h +++ b/widgets/displaytext.h @@ -30,12 +30,14 @@ public: void displayDecodedText(DecodedText const& decodedText, QString const& myCall, QString const& mode, bool displayDXCCEntity, LogBook const& logBook, QString const& currentBand=QString {}, bool ppfx=false, bool bCQonly=false, - bool haveFSpread = false, float fSpread = 0.); + bool haveFSpread = false, float fSpread = 0.0, bool bDisplayPoints=false, int points=-99); void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode, double TRperiod); void displayQSY(QString text); void displayFoxToBeCalled(QString t, QColor bg = QColor {}, QColor fg = QColor {}); void new_period (); QString CQPriority(){return m_CQPriority;}; + qint32 m_points; + bool m_bDisplayPoints; Q_SIGNAL void selectCallsign (Qt::KeyboardModifiers); Q_SIGNAL void erased (); diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 62e75437d..ab30181d6 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -60,6 +60,7 @@ #include "fastgraph.h" #include "about.h" #include "messageaveraging.h" +#include "activeStations.h" #include "colorhighlighting.h" #include "widegraph.h" #include "sleep.h" @@ -179,6 +180,8 @@ extern "C" { void chk_samples_(int* m_ihsym,int* k, int* m_hsymStop); void save_dxbase_(char* dxbase, FCL len); + + void indexx_(float arr[], int* n, int indx[]); } int volatile itone[MAX_NUM_SYMBOLS]; //Audio tones for all Tx symbols @@ -742,6 +745,24 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, } }); + // ensure a balanced layout of the mode buttons + qreal pointSize = m_config.text_font().pointSizeF(); + if (pointSize < 12) { + ui->houndButton->setMaximumWidth(40); + ui->ft8Button->setMaximumWidth(40); + ui->ft4Button->setMaximumWidth(40); + ui->msk144Button->setMaximumWidth(40); + ui->q65Button->setMaximumWidth(40); + ui->jt65Button->setMaximumWidth(40); + } else { + ui->houndButton->setMinimumWidth(0); + ui->ft8Button->setMinimumWidth(0); + ui->ft4Button->setMinimumWidth(0); + ui->msk144Button->setMinimumWidth(0); + ui->q65Button->setMinimumWidth(0); + ui->jt65Button->setMinimumWidth(0); + } + // hook up save WAV file exit handling connect (&m_saveWAVWatcher, &QFutureWatcher::finished, [this] { // extract the promise from the future @@ -851,6 +872,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, auto dBm = int ((10. * i / 3.) + .5); ui->TxPowerComboBox->addItem (QString {"%1 dBm %2"}.arg (dBm).arg (power[i]), dBm); } + ui->respondComboBox->addItem("CQ: None"); + ui->respondComboBox->addItem("CQ: First"); + ui->respondComboBox->addItem("CQ: Max Dist"); m_dateTimeRcvdRR73=QDateTime::currentDateTimeUtc(); m_dateTimeSentTx3=QDateTime::currentDateTimeUtc(); @@ -1122,7 +1146,8 @@ void MainWindow::writeSettings() m_settings->setValue ("MsgAvgDisplayed", m_msgAvgWidget && m_msgAvgWidget->isVisible ()); m_settings->setValue ("FoxLogDisplayed", m_foxLogWindow && m_foxLogWindow->isVisible ()); m_settings->setValue ("ContestLogDisplayed", m_contestLogWindow && m_contestLogWindow->isVisible ()); - m_settings->setValue("CallFirst",ui->cbFirst->isChecked()); + m_settings->setValue ("ActiveStationsDisplayed", m_ActiveStationsWidget && m_ActiveStationsWidget->isVisible ()); + m_settings->setValue("RespondCQ",ui->respondComboBox->currentIndex()); m_settings->setValue("HoundSort",ui->comboBoxHoundSort->currentIndex()); m_settings->setValue("FoxNlist",ui->sbNlist->value()); m_settings->setValue("FoxNslots",ui->sbNslots->value()); @@ -1178,6 +1203,7 @@ void MainWindow::writeSettings() m_settings->setValue ("AutoClearAvg", ui->actionAuto_Clear_Avg->isChecked ()); m_settings->setValue("SplitterState",ui->decodes_splitter->saveState()); m_settings->setValue("Blanker",ui->sbNB->value()); + m_settings->setValue("Score",m_score); { QList coeffs; // suitable for QSettings @@ -1198,7 +1224,7 @@ void MainWindow::writeSettings() void MainWindow::readSettings() { ui->cbAutoSeq->setVisible(false); - ui->cbFirst->setVisible(false); + ui->respondComboBox->setVisible(false); m_settings->beginGroup("MainWindow"); std::array the_geometries; the_geometries[0] = m_settings->value ("geometry", saveGeometry ()).toByteArray (); @@ -1220,7 +1246,8 @@ void MainWindow::readSettings() auto displayMsgAvg = m_settings->value ("MsgAvgDisplayed", false).toBool (); auto displayFoxLog = m_settings->value ("FoxLogDisplayed", false).toBool (); auto displayContestLog = m_settings->value ("ContestLogDisplayed", false).toBool (); - ui->cbFirst->setChecked(m_settings->value("CallFirst",true).toBool()); + bool displayActiveStations = m_settings->value ("ActiveStationsDisplayed", false).toBool (); + ui->respondComboBox->setCurrentIndex(m_settings->value("RespondCQ",0).toInt()); ui->comboBoxHoundSort->setCurrentIndex(m_settings->value("HoundSort",3).toInt()); ui->sbNlist->setValue(m_settings->value("FoxNlist",12).toInt()); m_Nslots=m_settings->value("FoxNslots",5).toInt(); @@ -1274,6 +1301,7 @@ void MainWindow::readSettings() ui->RoundRobin->setCurrentText(m_settings->value("RoundRobin",tr("Random")).toString()); m_dBm=m_settings->value("dBm",37).toInt(); m_send_RR73=m_settings->value("RR73",false).toBool(); + m_score=m_settings->value("Score",0).toInt(); if(m_send_RR73) { m_send_RR73=false; on_txrb4_doubleClicked(); @@ -1320,6 +1348,10 @@ void MainWindow::readSettings() if(displayMsgAvg) on_actionMessage_averaging_triggered(); if (displayFoxLog) on_fox_log_action_triggered (); if (displayContestLog) on_contest_log_action_triggered (); + if(displayActiveStations) { + on_actionActiveStations_triggered(); +// QFile f {m_config.writeable_data_dir ().absoluteFilePath ("activeCalls.txt")}; + } } void MainWindow::checkMSK144ContestType() @@ -1490,8 +1522,8 @@ void MainWindow::dataSink(qint64 frames) freqcal_(&dec_data.d2[0], &k, &nkhz, &RxFreq, &ftol, &line[0], (FCL)80); QString t=QString::fromLatin1(line); DecodedText decodedtext {t}; - ui->decodedTextBrowser->displayDecodedText (decodedtext, m_config.my_callsign (), m_mode, m_config.DXCC (), - m_logBook, m_currentBand, m_config.ppfx ()); + ui->decodedTextBrowser->displayDecodedText (decodedtext, m_config.my_callsign(), + m_mode, m_config.DXCC(), m_logBook, m_currentBand, m_config.ppfx()); if (ui->measure_check_box->isChecked ()) { // Append results text to file "fmt.all". QFile f {m_config.writeable_data_dir ().absoluteFilePath ("fmt.all")}; @@ -1952,14 +1984,12 @@ void MainWindow::on_actionAbout_triggered() //Display "About" void MainWindow::on_autoButton_clicked (bool checked) { m_auto = checked; + m_maxPoints=-1; if (checked - && ui->cbFirst->isVisible () && ui->cbFirst->isChecked() + && ui->respondComboBox->isVisible () && ui->respondComboBox->currentText() != "CQ: None" && CALLING == m_QSOProgress) { m_bAutoReply = false; // ready for next - m_bCallingCQ = true; // allows tail-enders to be picked up - ui->cbFirst->setStyleSheet ("QCheckBox{color:red}"); - } else { - ui->cbFirst->setStyleSheet(""); + m_bCallingCQ = true; // allows tail-enders to be picked up } if (!checked) m_bCallingCQ = false; statusUpdate (); @@ -2022,9 +2052,10 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } return; case Qt::Key_C: - if(m_mode=="FT4" && e->modifiers() & Qt::AltModifier) { - bool b=ui->cbFirst->isChecked(); - ui->cbFirst->setChecked(!b); + if(e->modifiers() & Qt::AltModifier) { + int n=ui->respondComboBox->currentIndex()+1; + if(n>2) n=0; + ui->respondComboBox->setCurrentIndex(n); } return; case Qt::Key_D: @@ -2085,8 +2116,9 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } case Qt::Key_F6: if(bAltF1F6) { - bool b=ui->cbFirst->isChecked(); - ui->cbFirst->setChecked(!b); + int n=ui->respondComboBox->currentIndex()+1; + if(n>2) n=0; + ui->respondComboBox->setCurrentIndex(n); } else { if(e->modifiers() & Qt::ShiftModifier) { on_actionDecode_remaining_files_in_directory_triggered(); @@ -2745,6 +2777,22 @@ void MainWindow::on_actionMessage_averaging_triggered() m_msgAvgWidget->activateWindow(); } +void MainWindow::on_actionActiveStations_triggered() +{ + if(m_ActiveStationsWidget == NULL) { + m_ActiveStationsWidget.reset (new ActiveStations {m_settings, m_config.decoded_text_font ()}); + + // Connect signals from Message Averaging window + connect (this, &MainWindow::finished, m_ActiveStationsWidget.data (), &ActiveStations::close); + } + m_ActiveStationsWidget->showNormal(); + m_ActiveStationsWidget->raise(); + m_ActiveStationsWidget->activateWindow(); + connect(m_ActiveStationsWidget.data(), SIGNAL(callSandP(int)),this,SLOT(callSandP2(int))); + connect(m_ActiveStationsWidget.data(), SIGNAL(activeStationsDisplay()),this,SLOT(ARRL_Digi_Display())); + m_ActiveStationsWidget->setScore(m_score); +} + void MainWindow::on_actionOpen_triggered() //Open File { monitor (false); @@ -3230,6 +3278,8 @@ void MainWindow::decode() //decode() decodeBusy(true); } } + if((m_mode=="FT4" or (m_mode=="FT8" and m_ihsym==41) or m_diskData) and + m_ActiveStationsWidget != NULL) m_ActiveStationsWidget->erase(); } void::MainWindow::fast_decode_done() @@ -3310,15 +3360,11 @@ void MainWindow::decodeDone () mswait = 1000.0 * ( 1.6 * m_TRperiod - tdone ); } m_bDecoded=m_nDecodes>0; -// qDebug() << "aa 3316" << m_saveDecoded << m_saveAll << m_bDecoded << m_nDecodes -// << m_TRperiod << tdone << mswait; if(!m_diskData and !m_saveAll) { if(m_saveDecoded and (m_nDecodes==0)) { -// qDebug() << "bb 3319" << mswait; killFileTimer.start(mswait); //Kill at 3/4 period } } - if(m_mode!="FT8" or dec_data.params.nzhsym==50) m_nDecodes=0; dec_data.params.nagain=0; dec_data.params.ndiskdat=0; @@ -3335,16 +3381,200 @@ void MainWindow::decodeDone () MessageBox::information_message(this, tr("No more files to open.")); m_bNoMoreFiles=false; } + + if((m_mode=="FT4" or m_mode=="FT8") + and m_latestDecodeTime>=0 and m_ActiveStationsWidget!=NULL) { + if(!m_diskData and (m_nDecodes==0)) { + m_latestDecodeTime = (QDateTime::currentMSecsSinceEpoch()/1000) % 86400; + m_latestDecodeTime = int(m_latestDecodeTime/m_TRperiod); + m_latestDecodeTime = int(m_latestDecodeTime*m_TRperiod); + } + ARRL_Digi_Display(); // Update the ARRL_DIGI display + } + if(m_mode!="FT8" or dec_data.params.nzhsym==50) m_nDecodes=0; +} + +void MainWindow::ARRL_Digi_Update(DecodedText dt) +{ + // Extract information relevant for the ARRL Digi contest + QString deCall; + QString deGrid; + dt.deCallAndGrid(/*out*/deCall,deGrid); + ActiveCall ac; + RecentCall rc; + + if(deGrid.contains(grid_regexp)) { + if(!m_activeCall.contains(deCall) or deGrid!=m_activeCall.value(deCall).grid4) { + // Transmitting station's call is not already in QMap "m_activeCall", or grid has changed. + // Insert the call, grid, and associated fixed data into the list. + + double utch=0.0; + int nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter; + azdist_(const_cast (m_config.my_grid().left(4).toLatin1().constData()), + const_cast (deGrid.left(4).toLatin1().constData()),&utch, + &nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,(FCL)6,(FCL)6); + int points=nDkm/500; + if(nDkm > 500*points) points += 1; + points += 1; + ac.grid4=deGrid; + ac.bands="......."; + ac.az=nAz; + ac.points=points; + m_activeCall[deCall]=ac; + } + } + + m_points=-1; + if(m_activeCall.contains(deCall)) { + +// Don't display stations we already worked on this band. + QString band=m_config.bands()->find(m_freqNominal); + if(band=="160m" and m_activeCall[deCall].bands.indexOf("a")>=0) {m_recentCall.remove(deCall); return;} + if(band=="80m" and m_activeCall[deCall].bands.indexOf("b")>=0) {m_recentCall.remove(deCall); return;} + if(band=="40m" and m_activeCall[deCall].bands.indexOf("c")>=0) {m_recentCall.remove(deCall); return;} + if(band=="20m" and m_activeCall[deCall].bands.indexOf("d")>=0) {m_recentCall.remove(deCall); return;} + if(band=="15m" and m_activeCall[deCall].bands.indexOf("e")>=0) {m_recentCall.remove(deCall); return;} + if(band=="10m" and m_activeCall[deCall].bands.indexOf("f")>=0) {m_recentCall.remove(deCall); return;} + if(band=="6m" and m_activeCall[deCall].bands.indexOf("g")>=0) {m_recentCall.remove(deCall); return;} + + // Update the variable data for this deCall + rc.dialFreq=m_freqNominal; + rc.audioFreq=dt.frequencyOffset(); + rc.snr=dt.snr(); + m_latestDecodeTime=dt.timeInSeconds(); + rc.txEven = (m_latestDecodeTime % int(2*m_TRperiod)) > 0; + rc.ready2call=false; + bool bCQ=dt.messageWords()[0].left(3)=="CQ "; + if(bCQ or deGrid=="RR73" or deGrid=="73") rc.ready2call=true; + rc.decodeTime=m_latestDecodeTime; + m_recentCall[deCall]=rc; + m_points=m_activeCall.value(deCall).points; + } + updateRate(); +} + +void MainWindow::ARRL_Digi_Display() +{ + QMutableMapIterator icall(m_recentCall); + QString deCall,deGrid; + int age=0; + int i=0; + int maxAge=m_ActiveStationsWidget->maxAge(); + int points=0; + int maxPoints=0; + int indx[1000]; + float pts[1000]; + QStringList list; + + while (icall.hasNext()) { + icall.next(); + deCall=icall.key(); + age=int((m_latestDecodeTime - icall.value().decodeTime)/m_TRperiod + 0.5); + if(age<0) age=age + int(86400/m_TRperiod); + int itx=1; + if(icall.value().txEven) itx=0; + int snr=icall.value().snr; + int freq=icall.value().audioFreq; + if(age>maxAge) { + icall.remove(); + } else { + bool bReady=false; + if(age==0 and m_recentCall.value(deCall).ready2call) bReady=true; + + QString bands=m_activeCall[deCall].bands; + bool bWorkedOnBand=false; + if(m_currentBand=="160m" and bands.mid(0,1)!=".") bWorkedOnBand=true; + if(m_currentBand=="80m" and bands.mid(1,1)!=".") bWorkedOnBand=true; + if(m_currentBand=="40m" and bands.mid(2,1)!=".") bWorkedOnBand=true; + if(m_currentBand=="20m" and bands.mid(3,1)!=".") bWorkedOnBand=true; + if(m_currentBand=="15m" and bands.mid(4,1)!=".") bWorkedOnBand=true; + if(m_currentBand=="10m" and bands.mid(5,1)!=".") bWorkedOnBand=true; + if(m_currentBand=="6m" and bands.mid(6,1)!=".") bWorkedOnBand=true; + + if((bReady or !m_ActiveStationsWidget->readyOnly()) and !bWorkedOnBand) { + i++; + int az=m_activeCall[deCall].az; + deGrid=m_activeCall[deCall].grid4; + points=m_activeCall[deCall].points; + if(points>maxPoints) maxPoints=points; + float x=float(age)/(maxAge+1); + if(x>1.0) x=0; + pts[i-1]=points - x; + QString t1; + if(!bReady) t1 = t1.asprintf(" %3d %+2.2d %4d %1d %2d %4d",az,snr,freq,itx,age,points); + if(bReady) t1 = t1.asprintf(" %3d %+2.2d %4d %1d %2d*%4d",az,snr,freq,itx,age,points); +// t1 = (deCall + " ").left(6) + " " + m_activeCall[deCall].grid4 + t1 + " " + bands; + t1 = (deCall + " ").left(6) + " " + m_activeCall[deCall].grid4 + t1; + list.append(t1); + } + } + } + if(i==0) return; + int jz=i; + m_ActiveStationsWidget->setClickOK(false); + int maxRecent=qMin(i,m_ActiveStationsWidget->maxRecent()); + indexx_(pts,&jz,indx); + QString t; + i=0; + for(int j=jz-1; j>=0; j--) { + int k=indx[j]-1; + m_ready2call[i]=list[k]; + i++; + QString t1=QString::number(i) + ". "; + if(i<10) t1=" " + t1; + t += (t1 + list[k] + "\n"); + if(i>=maxRecent) break; + } + if(m_ActiveStationsWidget!=NULL) m_ActiveStationsWidget->displayRecentStations(t); + m_ActiveStationsWidget->setClickOK(true); +} + +void MainWindow::callSandP2(int n) +{ + if(m_ready2call[n]=="") return; + QStringList w=m_ready2call[n].split(' ', SkipEmptyParts); + m_deCall=w[0]; + m_deGrid=w[1]; + m_bDoubleClicked=true; //### needed? + ui->dxCallEntry->setText(m_deCall); + ui->dxGridEntry->setText(m_deGrid); + genStdMsgs(w[3]); //### real SNR would be better here? + ui->RxFreqSpinBox->setValue(w[4].toInt()); + setTxMsg(1); + m_txFirst = (w[5]=="0"); + ui->txFirstCheckBox->setChecked(m_txFirst); + if (!ui->autoButton->isChecked()) ui->autoButton->click(); // Enable Tx + if(m_transmitting) m_restart=true; +} + +void MainWindow::activeWorked(QString call, QString band) +{ + QString bands=m_activeCall[call].bands; + QByteArray ba=bands.toLatin1(); + if(band=="160m") ba[0]='a'; + if(band=="80m") ba[1]='b'; + if(band=="40m") ba[2]='c'; + if(band=="20m") ba[3]='d'; + if(band=="15m") ba[4]='e'; + if(band=="10m") ba[5]='f'; + if(band=="6m") ba[6]='g'; + m_activeCall[call].bands=QString::fromLatin1(ba); } void MainWindow::readFromStdout() //readFromStdout { + bool bDisplayPoints = false; + if(m_ActiveStationsWidget!=NULL) { + bDisplayPoints=(m_mode=="FT4" or m_mode=="FT8") and + (m_config.special_op_id()==SpecOp::ARRL_DIGI or m_ActiveStationsWidget->isVisible()); + } while(proc_jt9.canReadLine()) { auto line_read = proc_jt9.readLine (); if (auto p = std::strpbrk (line_read.constData (), "\n\r")) { // truncate before line ending chars line_read = line_read.left (p - line_read.constData ()); } + if(bDisplayPoints) line_read=line_read.replace("a7"," "); bool haveFSpread {false}; float fSpread {0.}; if (m_mode.startsWith ("FST4")) @@ -3460,10 +3690,19 @@ void MainWindow::readFromStdout() //readFromStdout } } else { DecodedText decodedtext1=decodedtext0; + if((m_mode=="FT4" or m_mode=="FT8") and bDisplayPoints and decodedtext1.isStandardMessage()) { + ARRL_Digi_Update(decodedtext1); + } ui->decodedTextBrowser->displayDecodedText (decodedtext1, m_config.my_callsign (), m_mode, m_config.DXCC (), m_logBook, m_currentBand, m_config.ppfx (), ui->cbCQonly->isVisible() && ui->cbCQonly->isChecked(), - haveFSpread, fSpread); + haveFSpread, fSpread, bDisplayPoints, m_points); + if((m_mode=="FT4" or m_mode=="FT8") and bDisplayPoints and decodedtext1.isStandardMessage()) { + QString deCall,deGrid; + decodedtext.deCallAndGrid(/*out*/deCall,deGrid); + bool bWorkedOnBand=(ui->decodedTextBrowser->CQPriority()!="New Call on Band") and ui->decodedTextBrowser->CQPriority()!=""; + if(bWorkedOnBand) activeWorked(deCall,m_currentBand); + } if (m_config.highlight_DXcall () && (m_hisCall!="") && ((decodedtext.string().contains(QRegularExpression {"(\\w+) " + m_hisCall})) || (decodedtext.string().contains(QRegularExpression {"(\\w+) <" + m_hisCall +">"})) @@ -3493,7 +3732,6 @@ void MainWindow::readFromStdout() //readFromStdout } } } - } } @@ -3508,29 +3746,71 @@ void MainWindow::readFromStdout() //readFromStdout if (parts.size() > 6) { auto for_us = parts[5].contains (m_baseCall) || ("DE" == parts[5] && qAbs (ui->RxFreqSpinBox->value () - audioFreq) <= ftol); - if(m_baseCall == m_config.my_callsign()) - { - if (m_baseCall != parts[5]) - { - for_us=false; - } + if(m_baseCall == m_config.my_callsign()) { + if (m_baseCall != parts[5]) for_us=false; + } else { + if (m_config.my_callsign () != parts[5]) { +// Same base call as ours but different prefix or suffix. Rare but can happen with +// multi-station special events. + for_us = false; } - else - { - if (m_config.my_callsign () != parts[5]) - { - for_us = false; // same base call as ours but - // different prefix or suffix, rare - // but can happen with multi station - // special events - } + } + if(m_bCallingCQ && !m_bAutoReply && for_us && SpecOp::FOX > m_config.special_op_id()) { + bool bProcessMsgNormally=ui->respondComboBox->currentText()=="CQ: First" or + (ui->respondComboBox->currentText()=="CQ: Max Dist" and m_ActiveStationsWidget==NULL) or + (m_ActiveStationsWidget!=NULL and !m_ActiveStationsWidget->isVisible()); + QString t=decodedtext.messageWords()[4]; + if(t.contains("R+") or t.contains("R-") or t=="R" or t=="RRR" or t=="RR73") bProcessMsgNormally=true; + if(bProcessMsgNormally) { + m_bDoubleClicked=true; + m_bAutoReply = true; + processMessage (decodedtext); } - if(m_bCallingCQ && !m_bAutoReply && for_us && ui->cbFirst->isChecked() and - SpecOp::FOX > m_config.special_op_id()) { - m_bDoubleClicked=true; - m_bAutoReply = true; - if(SpecOp::FOX != m_config.special_op_id()) processMessage (decodedtext); - ui->cbFirst->setStyleSheet(""); + + if(!bProcessMsgNormally and m_ActiveStationsWidget and ui->respondComboBox->currentText()=="CQ: Max Dist") { + QString deCall; + QString deGrid; + decodedtext.deCallAndGrid(/*out*/deCall,deGrid); + if(deGrid.contains(grid_regexp) or + (deGrid.contains("+") or deGrid.contains("-"))) { + int points=0; + if(m_activeCall.contains(deCall)) { + points=m_activeCall[deCall].points; + deGrid=m_activeCall[deCall].grid4; + } else if(deGrid.contains(grid_regexp)) { + double utch=0.0; + int nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter; + azdist_(const_cast ((m_config.my_grid () + " ").left (6).toLatin1 ().constData ()), + const_cast ((deGrid + " ").left(6).toLatin1 ().constData ()),&utch, + &nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,(FCL)6,(FCL)6); + points=nDkm/500; + if(nDkm > 500*points) points += 1; + points += 1; + } + if(points>m_maxPoints) { + m_maxPoints=points; + m_deCall=deCall; + m_bDoubleClicked=true; + ui->dxCallEntry->setText(deCall); + int m_ntx=2; + bool bContest=m_config.special_op_id()==SpecOp::NA_VHF or m_config.special_op_id()==SpecOp::ARRL_DIGI; + if(bContest) m_ntx=3; + if(deGrid.contains(grid_regexp)) { + m_deGrid=deGrid; + ui->dxGridEntry->setText(deGrid); + } else { + m_ntx=3; + } + if(m_ntx==2) m_QSOProgress = REPORT; + if(m_ntx==3) m_QSOProgress = ROGER_REPORT; + genStdMsgs(QString::number(decodedtext.snr())); + ui->RxFreqSpinBox->setValue(decodedtext.frequencyOffset()); + setTxMsg(m_ntx); + m_currentMessageType=m_ntx; + } + } + } + } if(SpecOp::FOX==m_config.special_op_id() and decodedtext.string().contains(" DE ")) for_us=true; //Hound with compound callsign if(SpecOp::FOX==m_config.special_op_id() and for_us and (audioFreq<1000)) bDisplayRight=true; @@ -3546,7 +3826,7 @@ void MainWindow::readFromStdout() //readFromStdout // or contains MyCall if(!m_bBestSPArmed or m_mode!="FT4") { ui->decodedTextBrowser2->displayDecodedText (decodedtext0, m_config.my_callsign (), m_mode, m_config.DXCC (), - m_logBook, m_currentBand, m_config.ppfx ()); + m_logBook, m_currentBand, m_config.ppfx (), false, false, 0.0, bDisplayPoints, m_points); } m_QSOText = decodedtext.string ().trimmed (); } @@ -3750,7 +4030,6 @@ void MainWindow::pskPost (DecodedText const& decodedtext) void MainWindow::killFile () { -// qDebug() << "cc 3725" << m_saveDecoded << m_saveAll << m_bDecoded << m_nDecodes << m_fnameWE; if (m_fnameWE.size () && !(m_saveAll || (m_saveDecoded && m_bDecoded))) { QFile f1 {m_fnameWE + ".wav"}; if(f1.exists()) f1.remove(); @@ -4183,13 +4462,7 @@ void MainWindow::guiUpdate() } m_bCallingCQ = 6 == m_ntx || m_currentMessage.contains (QRegularExpression {"^(CQ|QRZ) "}); - if(m_mode=="FT8" or m_mode=="FT4") { - if(m_bCallingCQ && ui->cbFirst->isVisible () && ui->cbFirst->isChecked ()) { - ui->cbFirst->setStyleSheet("QCheckBox{color:red}"); - } else { - ui->cbFirst->setStyleSheet(""); - } - } + m_maxPoints=-1; if (m_tune) { m_currentMessage = "TUNE"; @@ -4231,7 +4504,8 @@ void MainWindow::guiUpdate() } } - bool b=("FT8"==m_mode or "FT4"==m_mode or "Q65"==m_mode) and ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isEnabled () && ui->cbAutoSeq->isChecked (); + bool b=("FT8"==m_mode or "FT4"==m_mode or "Q65"==m_mode) and ui->cbAutoSeq->isVisible () + && ui->cbAutoSeq->isEnabled () && ui->cbAutoSeq->isChecked (); if(is_73 and (m_config.disable_TX_on_73() or b)) { m_nextCall=""; //### Temporary: disable use of "TU;" messages; if(m_nextCall!="") { @@ -4344,7 +4618,8 @@ void MainWindow::guiUpdate() (SpecOp::NA_VHF==m_config.special_op_id() or SpecOp::FIELD_DAY==m_config.special_op_id() or SpecOp::RTTY==m_config.special_op_id() or - SpecOp::WW_DIGI==m_config.special_op_id()) ) { + SpecOp::WW_DIGI==m_config.special_op_id() or + SpecOp::ARRL_DIGI==m_config.special_op_id()) ) { //We're in a contest-like mode other than EU_VHF: start QSO with Tx2. ui->tx1->setEnabled(false); ui->txb1->setEnabled(false); @@ -4478,9 +4753,10 @@ void MainWindow::startTx2() t=ui->tx6->text(); if(t.mid(0,1)=="#") snr=t.mid(1,5).toDouble(); if(snr>0.0 or snr < -50.0) snr=99.0; - if((m_ntx==6 or m_ntx==7) and m_config.force_call_1st()) { + if((m_ntx==6 or m_ntx==7) and m_config.force_call_1st() and + ui->respondComboBox->currentIndex()==0) { ui->cbAutoSeq->setChecked(true); - ui->cbFirst->setChecked(true); + ui->respondComboBox->setCurrentIndex(1); } transmit (snr); ui->signal_meter_widget->setValue(0,0); @@ -4961,7 +5237,9 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie && (message_words.at(3).contains(qso_partner_base_call) or m_bDoubleClicked or bEU_VHF_w2 or (m_QSOProgress==CALLING))) { if(message_words.at(4).contains(grid_regexp) and SpecOp::EU_VHF!=m_config.special_op_id()) { - if((SpecOp::NA_VHF==m_config.special_op_id() or SpecOp::WW_DIGI==m_config.special_op_id()) and bContestOK){ + if((SpecOp::NA_VHF==m_config.special_op_id() or SpecOp::WW_DIGI==m_config.special_op_id() or + SpecOp::ARRL_DIGI==m_config.special_op_id() ) + and bContestOK) { setTxMsg(3); m_QSOProgress=ROGER_REPORT; } else { @@ -5209,6 +5487,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } // if we get here then we are reacting to the message if (m_bAutoReply) m_bCallingCQ = CALLING == m_QSOProgress; + m_maxPoints=-1; if (ui->RxFreqSpinBox->isEnabled () and m_mode != "MSK144" and !shift) { ui->RxFreqSpinBox->setValue (frequency); //Set Rx freq } @@ -5334,6 +5613,7 @@ void MainWindow::genCQMsg () if(SpecOp::FIELD_DAY == m_config.special_op_id()) m_cqStr="FD"; if(SpecOp::RTTY == m_config.special_op_id()) m_cqStr="RU"; if(SpecOp::WW_DIGI == m_config.special_op_id()) m_cqStr="WW"; + if(SpecOp::ARRL_DIGI == m_config.special_op_id()) m_cqStr="TEST"; if( tlist.at(1)==my_callsign ) { t="CQ " + m_cqStr + " " + tlist.at(1) + " " + tlist.at(2); } else { @@ -5443,6 +5723,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) } if(SpecOp::NA_VHF==m_config.special_op_id()) sent=my_grid; if(SpecOp::WW_DIGI==m_config.special_op_id()) sent=my_grid; + if(SpecOp::ARRL_DIGI==m_config.special_op_id()) sent=my_grid; if(SpecOp::FIELD_DAY==m_config.special_op_id()) sent=m_config.Field_Day_Exchange(); if(SpecOp::RTTY==m_config.special_op_id()) { sent=rst + m_config.RTTY_Exchange(); @@ -5978,6 +6259,10 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button m_xSent=m_config.my_grid().left(4); m_xRcvd=m_hisGrid; break; + case SpecOp::ARRL_DIGI: + m_xSent=m_config.my_grid().left(4); + m_xRcvd=m_hisGrid; + break; default: break; } @@ -6028,12 +6313,43 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, ui->sbSerialNumber->setValue(ui->sbSerialNumber->value() + 1); } + if(m_ActiveStationsWidget!=NULL) { + QString band=m_config.bands()->find(dial_freq); + activeWorked(call,band); + int points=m_activeCall[call].points; + m_score += points; + ARRL_logged al; + al.time=QDateTime::currentDateTimeUtc(); + al.band=band; + al.points=points; + m_arrl_log.append(al); + updateRate(); + } + m_xSent.clear (); m_xRcvd.clear (); if (m_config.clear_DXcall ()) ui->dxCallEntry->clear (); if (m_config.clear_DXgrid ()) ui->dxGridEntry->clear (); } +void MainWindow::updateRate() +{ + int iz=m_arrl_log.size(); + int rate=0; + int nbc=0; + double hrDiff; + + for(int i=iz-1; i>=0; i--) { + hrDiff = m_arrl_log[i].time.msecsTo(QDateTime::currentDateTimeUtc())/3600000.0; + if(hrDiff > 1.0) break; + rate += m_arrl_log[i].points; + if(isetRate(rate); + m_ActiveStationsWidget->setScore(m_score); + m_ActiveStationsWidget->setBandChanges(nbc); +} + qint64 MainWindow::nWidgets(QString t) { Q_ASSERT(t.length()==N_WIDGETS); @@ -6087,8 +6403,7 @@ void MainWindow::displayWidgets(qint64 n) if(i==24) ui->actionEnable_AP_FT8->setVisible (b); if(i==25) ui->actionEnable_AP_JT65->setVisible (b); if(i==26) ui->actionEnable_AP_DXcall->setVisible (b); - if(i==27) ui->cbFirst->setVisible(b); - // if(i==28) ui->labNextCall->setVisible(b); + if(i==27) ui->respondComboBox->setVisible(b); if(i==29) ui->measure_check_box->setVisible(b); if(i==30) ui->labDXped->setVisible(b); if(i==31) ui->cbRxAll->setVisible(b); @@ -6314,13 +6629,19 @@ void MainWindow::on_actionFT8_triggered() switch_mode (Modes::FT8); } + if(m_config.special_op_id() != SpecOp::HOUND) { + ui->houndButton->setChecked(false); + ui->houndButton->setStyleSheet(""); + } + if (SpecOp::NONE < m_config.special_op_id () && SpecOp::FOX > m_config.special_op_id ()) { QString t0=""; - if(SpecOp::NA_VHF==m_config.special_op_id()) t0+="NA VHF"; - if(SpecOp::EU_VHF==m_config.special_op_id()) t0+="EU VHF"; - if(SpecOp::FIELD_DAY==m_config.special_op_id()) t0+="Field Day"; - if(SpecOp::RTTY==m_config.special_op_id()) t0+="RTTY"; - if(SpecOp::WW_DIGI==m_config.special_op_id()) t0+="WW_DIGI"; + if(SpecOp::NA_VHF==m_config.special_op_id()) t0="NA VHF"; + if(SpecOp::EU_VHF==m_config.special_op_id()) t0="EU VHF"; + if(SpecOp::FIELD_DAY==m_config.special_op_id()) t0="Field Day"; + if(SpecOp::RTTY==m_config.special_op_id()) t0="RTTY"; + if(SpecOp::WW_DIGI==m_config.special_op_id()) t0="WW_DIGI"; + if(SpecOp::ARRL_DIGI==m_config.special_op_id()) t0="ARRL_DIGI"; if(t0=="") { ui->labDXped->setVisible(false); } else { @@ -6530,8 +6851,9 @@ void MainWindow::on_actionQ65_triggered() if(SpecOp::NA_VHF==m_config.special_op_id()) t0="NA VHF"; if(SpecOp::EU_VHF==m_config.special_op_id()) t0="EU VHF"; if(SpecOp::FIELD_DAY==m_config.special_op_id()) t0="Field Day"; - if(SpecOp::RTTY==m_config.special_op_id()) t0+="RTTY"; - if(SpecOp::WW_DIGI==m_config.special_op_id()) t0+="WW_DIGI"; + if(SpecOp::RTTY==m_config.special_op_id()) t0="RTTY"; + if(SpecOp::WW_DIGI==m_config.special_op_id()) t0="WW_DIGI"; + if(SpecOp::ARRL_DIGI==m_config.special_op_id()) t0="ARRL_DIGI"; if(t0=="") { ui->labDXped->setVisible(false); } else { @@ -6603,8 +6925,8 @@ void MainWindow::on_actionMSK144_triggered() statusChanged(); QString t0=""; - if(SpecOp::NA_VHF==m_config.special_op_id()) t0+="NA VHF"; - if(SpecOp::EU_VHF==m_config.special_op_id()) t0+="EU VHF"; + if(SpecOp::NA_VHF==m_config.special_op_id()) t0="NA VHF"; + if(SpecOp::EU_VHF==m_config.special_op_id()) t0="EU VHF"; if(t0=="") { ui->labDXped->setVisible(false); } else { @@ -6900,6 +7222,9 @@ void MainWindow::on_reset_cabrillo_log_action_triggered () { if(m_config.RTTY_Exchange()!="SCC") ui->sbSerialNumber->setValue(1); m_logBook.contest_log ()->reset (); + m_activeCall.clear(); //Erase the QMap of active calls + m_score=0; + m_ActiveStationsWidget->setScore(0); } } @@ -7057,7 +7382,7 @@ void MainWindow::on_rptSpinBox_valueChanged(int n) void MainWindow::on_tuneButton_clicked (bool checked) { - tuneATU_Timer.start (120000); // tune watchdog (120s) + if (!m_config.Tune_watchdog_disabled ()) tuneATU_Timer.start (90000); // tune watchdog (90s) static bool lastChecked = false; if (lastChecked == checked) return; lastChecked = checked; @@ -7117,7 +7442,7 @@ void MainWindow::on_stopTxButton_clicked() //Stop Tx m_btxok=false; m_bCallingCQ = false; m_bAutoReply = false; // ready for next - ui->cbFirst->setStyleSheet (""); + m_maxPoints=-1; } void MainWindow::rigOpen () @@ -7264,6 +7589,12 @@ void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const& if (m_lastDialFreq != m_freqNominal && (m_mode != "MSK144" || !(ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked()))) { + + if(m_lastDialFreq != m_freqNominal and m_ActiveStationsWidget != NULL) { + m_recentCall.clear(); + m_ActiveStationsWidget->erase(); + } + m_lastDialFreq = m_freqNominal; m_secBandChanged=QDateTime::currentMSecsSinceEpoch()/1000; pskSetLocal (); @@ -7355,6 +7686,12 @@ void MainWindow::transmit (double snr) true, false, snr, m_TRperiod); } + if((m_mode=="FT4" or m_mode=="FT8") and m_maxPoints>0 and SpecOp::ARRL_DIGI==m_config.special_op_id()) { + ui->dxCallEntry->setText(m_deCall); + ui->dxGridEntry->setText(m_deGrid); + genStdMsgs("-10"); + } + if (m_mode == "FT8") { // toneSpacing=12000.0/1920.0; toneSpacing=-3; @@ -7980,8 +8317,7 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout } m_nWSPRdecodes=0; ui->DecodeButton->setChecked (false); - if (m_uploadWSPRSpots - && m_config.is_transceiver_online ()) { // need working rig control + if(m_uploadWSPRSpots && m_config.is_transceiver_online()) { // need working rig control #if QT_VERSION >= QT_VERSION_CHECK (5, 15, 0) uploadTimer.start(QRandomGenerator::global ()->bounded (0, 20000)); // Upload delay #else @@ -7996,7 +8332,6 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout m_decoderBusy = false; statusUpdate (); } else { - int n=t.length(); t=t.mid(0,n-2) + " "; t.remove(QRegExp("\\s+$")); @@ -8554,21 +8889,9 @@ void MainWindow::on_cbCQonly_toggled(bool) decodeBusy(true); } -void MainWindow::on_cbFirst_toggled(bool b) -{ - if (b) { - if (m_auto && CALLING == m_QSOProgress) { - ui->cbFirst->setStyleSheet ("QCheckBox{color:red}"); - } - } else { - ui->cbFirst->setStyleSheet (""); - } -} - void MainWindow::on_cbAutoSeq_toggled(bool b) { - if(!b) ui->cbFirst->setChecked(false); - ui->cbFirst->setVisible((m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" + ui->respondComboBox->setVisible((m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" or m_mode=="Q65") and b); } @@ -9313,18 +9636,19 @@ void MainWindow::chkFT4() { if(m_mode!="FT4") return; ui->cbAutoSeq->setEnabled(true); - ui->cbFirst->setVisible(true); - ui->cbFirst->setEnabled(true); + ui->respondComboBox->setVisible(true); + ui->respondComboBox->setEnabled(true); ui->labDXped->setVisible(m_config.special_op_id()!=SpecOp::NONE); - ui->cbFirst->setVisible(ui->cbAutoSeq->isChecked()); + ui->respondComboBox->setVisible(ui->cbAutoSeq->isChecked()); if (SpecOp::NONE < m_config.special_op_id () && SpecOp::FOX > m_config.special_op_id ()) { QString t0=""; - if(SpecOp::NA_VHF==m_config.special_op_id()) t0+="NA VHF"; - if(SpecOp::EU_VHF==m_config.special_op_id()) t0+="EU VHF"; - if(SpecOp::FIELD_DAY==m_config.special_op_id()) t0+="Field Day"; - if(SpecOp::RTTY==m_config.special_op_id()) t0+="RTTY"; - if(SpecOp::WW_DIGI==m_config.special_op_id()) t0+="WW_DIGI"; + if(SpecOp::NA_VHF==m_config.special_op_id()) t0="NA VHF"; + if(SpecOp::EU_VHF==m_config.special_op_id()) t0="EU VHF"; + if(SpecOp::FIELD_DAY==m_config.special_op_id()) t0="Field Day"; + if(SpecOp::RTTY==m_config.special_op_id()) t0="RTTY"; + if(SpecOp::WW_DIGI==m_config.special_op_id()) t0="WW_DIGI"; + if(SpecOp::ARRL_DIGI==m_config.special_op_id()) t0="ARRL_DIGI"; if(t0=="") { ui->labDXped->setVisible(false); } else { @@ -9488,7 +9812,7 @@ void MainWindow::on_ft8Button_clicked() { ui->houndButton->setChecked(false); ui->houndButton->setStyleSheet(""); - m_config.setSpecial_None(); + if(m_config.special_op_id()==SpecOp::HOUND) m_config.setSpecial_None(); on_actionFT8_triggered(); } @@ -9496,7 +9820,7 @@ void MainWindow::on_ft4Button_clicked() { ui->houndButton->setChecked(false); ui->houndButton->setStyleSheet(""); - m_config.setSpecial_None(); + if(m_config.special_op_id()==SpecOp::HOUND) m_config.setSpecial_None(); on_actionFT4_triggered(); } @@ -9504,7 +9828,7 @@ void MainWindow::on_msk144Button_clicked() { ui->houndButton->setChecked(false); ui->houndButton->setStyleSheet(""); - m_config.setSpecial_None(); + if(m_config.special_op_id()==SpecOp::HOUND) m_config.setSpecial_None(); on_actionMSK144_triggered(); } @@ -9512,7 +9836,7 @@ void MainWindow::on_q65Button_clicked() { ui->houndButton->setChecked(false); ui->houndButton->setStyleSheet(""); - m_config.setSpecial_None(); + if(m_config.special_op_id()==SpecOp::HOUND) m_config.setSpecial_None(); on_actionQ65_triggered(); } @@ -9520,6 +9844,6 @@ void MainWindow::on_jt65Button_clicked() { ui->houndButton->setChecked(false); ui->houndButton->setStyleSheet(""); - m_config.setSpecial_None(); + if(m_config.special_op_id()==SpecOp::HOUND) m_config.setSpecial_None(); on_actionJT65_triggered(); } diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 2fda134bb..400b1b4ca 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -78,6 +78,7 @@ class WideGraph; class LogQSO; class Transceiver; class MessageAveraging; +class ActiveStations; class FoxLogWindow; class CabrilloLogWindow; class ColorHighlighting; @@ -267,6 +268,7 @@ private slots: void stopTuneATU(); void auto_tx_mode(bool); void on_actionMessage_averaging_triggered(); + void on_actionActiveStations_triggered(); void on_contest_log_action_triggered (); void on_fox_log_action_triggered (); void on_actionColors_triggered(); @@ -281,7 +283,6 @@ private slots: void on_cbTx6_toggled(bool b); void on_cbMenus_toggled(bool b); void on_cbCQonly_toggled(bool b); - void on_cbFirst_toggled(bool b); void on_cbAutoSeq_toggled(bool b); void networkError (QString const&); void on_ClrAvgButton_clicked(); @@ -333,6 +334,7 @@ private slots: 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 , QString const& dx_grid, bool generate_messages); + void callSandP2(int nline); private: Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo, @@ -398,6 +400,7 @@ private: QScopedPointer m_prefixes; QScopedPointer m_mouseCmnds; QScopedPointer m_msgAvgWidget; + QScopedPointer m_ActiveStationsWidget; QScopedPointer m_foxLogWindow; QScopedPointer m_contestLogWindow; QScopedPointer m_colorHighlighting; @@ -489,6 +492,10 @@ private: qint32 m_earlyDecode=41; qint32 m_earlyDecode2=47; qint32 m_nDecodes=0; + qint32 m_maxPoints=-1; + qint32 m_latestDecodeTime=-1; + qint32 m_points=-99; + qint32 m_score=0; bool m_btxok; //True if OK to transmit bool m_diskData; @@ -640,6 +647,9 @@ private: QString m_fileDateTime; QString m_inQSOwith; QString m_BestCQpriority; + QString m_deCall; + QString m_deGrid; + QString m_ready2call[50]; QSet m_pfx; QSet m_sfx; @@ -667,6 +677,34 @@ private: }; QMap m_fixupQSO; //Key = HoundCall, value = info for QSO in progress + struct ActiveCall + { + QString grid4; + QString bands; + qint32 az; + qint32 points; + }; + QMap m_activeCall; //Key = callsign, value = grid4, az, points for ARRL_DIGI + + struct RecentCall + { + qint64 dialFreq; + qint32 audioFreq; + qint32 snr; + qint32 decodeTime; + bool txEven; + bool ready2call; + }; + QMap m_recentCall; //Key = callsign, value = snr, dialFreq, audioFreq, decodeTime + + struct ARRL_logged + { + QDateTime time; + QString band; + qint32 points; + }; + QList m_arrl_log; + QQueue m_houndQueue; //Selected Hounds available for starting a QSO QQueue m_foxQSOinProgress; //QSOs in progress: Fox has sent a report QQueue m_foxRateQueue; @@ -747,6 +785,7 @@ private: void CQTxFreq(); void useNextCall(); void abortQSO(); + void updateRate(); void write_all(QString txRx, QString message); bool isWorked(int itype, QString key, float fMHz=0, QString=""); @@ -787,6 +826,9 @@ private: void to_jt9(qint32 n, qint32 istart, qint32 idone); bool is77BitMode () const; void cease_auto_Tx_after_QSO (); + Q_SLOT void ARRL_Digi_Display(); + void ARRL_Digi_Update(DecodedText dt); + void activeWorked(QString call, QString band); }; extern int killbyname(const char* progName); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index b738dd2bf..bc7a4fb73 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 882 - 658 + 893 + 665 @@ -832,15 +832,18 @@ When not checked you can view the calibration results. - + - <html><head/><body><p>Check to call the first decoded responder to my CQ.</p></body></html> + <html><head/><body><p>Select <span style=" font-weight:600;">CQ: First</span> to respond automatically to the first decoded reply to your CQ. </p><p>Select <span style=" font-weight:600;">CQ: Max Pts</span> to respond automatically to the reply yielding most points in the ARRL International Digital Contest.</p><p>Select <span style=" font-weight:600;">CQ: None</span> to choose callers manually.</p></body></html> - - Check to call the first decoded responder to my CQ. + + - - Call 1st + + -1 + + + 3 @@ -2864,9 +2867,15 @@ QLabel[oob="true"] { - + 32 + 0 + + + + + 16777215 16777215 @@ -2883,9 +2892,15 @@ QLabel[oob="true"] { - + 32 + 0 + + + + + 16777215 16777215 @@ -2899,9 +2914,15 @@ QLabel[oob="true"] { - + 32 + 0 + + + + + 16777215 16777215 @@ -2915,9 +2936,15 @@ QLabel[oob="true"] { - + 32 + 0 + + + + + 16777215 16777215 @@ -2931,9 +2958,15 @@ QLabel[oob="true"] { - + 32 + 0 + + + + + 16777215 16777215 @@ -2947,9 +2980,15 @@ QLabel[oob="true"] { - + 32 + 0 + + + + + 16777215 16777215 @@ -2975,7 +3014,7 @@ QLabel[oob="true"] { 0 0 - 882 + 893 21 @@ -3013,6 +3052,7 @@ QLabel[oob="true"] { + @@ -3624,6 +3664,11 @@ QLabel[oob="true"] { Disable writing of ALL.TXT + + + Active Stations + + @@ -3706,7 +3751,6 @@ QLabel[oob="true"] { cbShMsgs cbFast9 cbAutoSeq - cbFirst cbTx6 cbSWL pbBestSP diff --git a/widgets/widgets.pri b/widgets/widgets.pri index 6a623d825..e8bdf5402 100644 --- a/widgets/widgets.pri +++ b/widgets/widgets.pri @@ -4,6 +4,7 @@ SOURCES += \ widgets/meterwidget.cpp widgets/signalmeter.cpp \ widgets/plotter.cpp widgets/widegraph.cpp widgets/about.cpp \ widgets/mainwindow.cpp widgets/messageaveraging.cpp \ + widgets/activeStations.cpp \ widgets/echoplot.cpp widgets/echograph.cpp widgets/fastgraph.cpp \ widgets/fastplot.cpp widgets/MessageBox.cpp \ widgets/colorhighlighting.cpp widgets/ExportCabrillo.cpp \ @@ -19,6 +20,7 @@ HEADERS += \ widgets/displaytext.h widgets/logqso.h widgets/LettersSpinBox.hpp \ widgets/FrequencyLineEdit.hpp widgets/FrequencyDeltaLineEdit.hpp widgets/signalmeter.h \ widgets/meterwidget.h widgets/messageaveraging.h \ + widgets/activeStations.h \ widgets/echoplot.h widgets/echograph.h widgets/fastgraph.h \ widgets/fastplot.h widgets/MessageBox.hpp widgets/colorhighlighting.h \ widgets/ExportCabrillo.h widgets/AbstractLogWindow.hpp \ @@ -31,6 +33,7 @@ FORMS += \ widgets/mainwindow.ui widgets/about.ui \ widgets/widegraph.ui widgets/astro.ui \ widgets/logqso.ui widgets/messageaveraging.ui \ + widgets/activeStations.ui \ widgets/echograph.ui widgets/fastgraph.ui \ widgets/colorhighlighting.ui widgets/ExportCabrillo.ui \ widgets/FoxLogWindow.ui widgets/CabrilloLogWindow.ui