diff --git a/APRSISClient.h b/APRSISClient.h index c7d30c8..ab9a772 100644 --- a/APRSISClient.h +++ b/APRSISClient.h @@ -20,6 +20,13 @@ public: static QString stripSSID(QString call); static QString replaceCallsignSuffixWithSSID(QString call, QString base); + bool isPasscodeValid(){ return m_localPasscode == QString::number(hashCallsign(m_localCall)); } + + void enqueueRaw(QString aprsFrame); + void processQueue(bool disconnect=true); + +public slots: + void setServer(QString host, quint16 port){ if(state() == QTcpSocket::ConnectedState){ disconnectFromHost(); @@ -40,15 +47,9 @@ public: m_localPasscode = passcode; } - bool isPasscodeValid(){ return m_localPasscode == QString::number(hashCallsign(m_localCall)); } - void enqueueSpot(QString by_call, QString from_call, QString grid, QString comment); void enqueueThirdParty(QString by_call, QString from_call, QString text); - void enqueueRaw(QString aprsFrame); - void processQueue(bool disconnect=true); - -public slots: void sendReports(){ if(m_paused) return; diff --git a/Configuration.cpp b/Configuration.cpp index 1db40ee..a5980fd 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -434,6 +434,8 @@ private: void delete_stations (); void insert_station (); + Q_SLOT void on_psk_reporter_check_box_toggled(bool checked); + Q_SLOT void on_enable_aprs_spotting_check_box_toggled(bool checked); Q_SLOT void on_notifications_check_box_toggled(bool checked); Q_SLOT void on_font_push_button_clicked (); Q_SLOT void on_tableFontButton_clicked(); @@ -640,6 +642,7 @@ private: bool id_after_73_; bool tx_qsy_allowed_; bool spot_to_reporting_networks_; + bool spot_to_aprs_; bool transmit_directed_; bool autoreply_on_at_startup_; bool autoreply_confirmation_; @@ -801,6 +804,11 @@ void Configuration::set_spot_to_reporting_networks (bool spot) } } +bool Configuration::spot_to_aprs() const +{ + return spot_to_reporting_networks() && m_->spot_to_aprs_; +} + bool Configuration::transmit_directed() const { return m_->transmit_directed_; } bool Configuration::autoreply_on_at_startup () const { // auto-reply cannot be on at startup if the callsign or grid is empty @@ -1544,6 +1552,7 @@ void Configuration::impl::initialize_models () ui_->CW_id_after_73_check_box->setChecked (id_after_73_); ui_->tx_qsy_check_box->setChecked (tx_qsy_allowed_); ui_->psk_reporter_check_box->setChecked (spot_to_reporting_networks_); + ui_->enable_aprs_spotting_check_box->setChecked(spot_to_aprs_); ui_->transmit_directed_check_box->setChecked(transmit_directed_); ui_->autoreply_on_check_box->setChecked (autoreply_on_at_startup_); ui_->autoreply_confirmation_check_box->setChecked (autoreply_confirmation_); @@ -1974,6 +1983,7 @@ void Configuration::impl::read_settings () monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool (); monitor_last_used_ = settings_->value ("MonitorLastUsed", false).toBool (); spot_to_reporting_networks_ = settings_->value ("PSKReporter", true).toBool (); + spot_to_aprs_ = settings_->value("SpotToAPRS", true).toBool(); write_logs_ = settings_->value("WriteLogs", true).toBool(); reset_activity_ = settings_->value("ResetActivity", false).toBool(); check_for_updates_ = settings_->value("CheckForUpdates", true).toBool(); @@ -2189,6 +2199,7 @@ void Configuration::impl::write_settings () settings_->setValue ("MonitorOFF", monitor_off_at_startup_); settings_->setValue ("MonitorLastUsed", monitor_last_used_); settings_->setValue ("PSKReporter", spot_to_reporting_networks_); + settings_->setValue ("SpotToAPRS", spot_to_aprs_); settings_->setValue ("WriteLogs", write_logs_); settings_->setValue ("ResetActivity", reset_activity_); settings_->setValue ("CheckForUpdates", check_for_updates_); @@ -2803,6 +2814,7 @@ void Configuration::impl::accept () callsign_aging_ = ui_->callsign_aging_spin_box->value(); activity_aging_ = ui_->activity_aging_spin_box->value(); spot_to_reporting_networks_ = ui_->psk_reporter_check_box->isChecked (); + spot_to_aprs_ = ui_->enable_aprs_spotting_check_box->isChecked(); id_interval_ = ui_->CW_id_interval_spin_box->value (); ntrials_ = ui_->sbNtrials->value (); txDelay_ = ui_->sbTxDelay->value (); @@ -2969,6 +2981,19 @@ void Configuration::impl::reject () QDialog::reject (); } +void Configuration::impl::on_psk_reporter_check_box_toggled(bool checked){ + ui_->enable_aprs_spotting_check_box->setEnabled(checked); + + bool spot = ui_->enable_aprs_spotting_check_box->isChecked(); + ui_->aprs_server_line_edit->setEnabled(spot && checked); + ui_->aprs_server_port_spin_box->setEnabled(spot && checked); +} + +void Configuration::impl::on_enable_aprs_spotting_check_box_toggled(bool checked){ + ui_->aprs_server_line_edit->setEnabled(checked); + ui_->aprs_server_port_spin_box->setEnabled(checked); +} + void Configuration::impl::on_notifications_check_box_toggled(bool checked){ ui_->notifications_table_widget->setEnabled(checked); } diff --git a/Configuration.hpp b/Configuration.hpp index 98cc4c4..64bb88b 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -138,6 +138,7 @@ public: bool tx_qsy_allowed () const; bool spot_to_reporting_networks () const; void set_spot_to_reporting_networks (bool); + bool spot_to_aprs() const; bool transmit_directed() const; bool autoreply_on_at_startup () const; bool autoreply_confirmation () const; diff --git a/Configuration.ui b/Configuration.ui index cbb8c19..cc2c8a6 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -2368,9 +2368,9 @@ both here. 0 - -60 + 0 746 - 682 + 667 @@ -2618,23 +2618,24 @@ This is used for reverse ping analysis which is very useful for assessing propagation and system performance. - Enable spotting to reporting networks (JS8NET, APRSIS, PSKReporter, etc) + Enable spotting to reporting networks (JS8NET, PSKReporter, etc) true - - - - - - - APRSIS Spotting - - - + + + + Enable spotting @APRSIS messages to the APRS-IS network + + + true + + + + QFormLayout::AllNonFixedFieldsGrow diff --git a/mainwindow.cpp b/mainwindow.cpp index 1e7b279..e49cb31 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -480,6 +480,18 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, // notification audio operates in its own thread at a lower priority m_notification->moveToThread(&m_notificationAudioThread); + // move the aprs client to its own network thread at a lower priority + m_aprsClient->moveToThread(&m_networkThread); + + // hook up the aprs client slots and signals and disposal + connect (this, &MainWindow::aprsClientEnqueueSpot, m_aprsClient, &APRSISClient::enqueueSpot); + connect (this, &MainWindow::aprsClientEnqueueThirdParty, m_aprsClient, &APRSISClient::enqueueThirdParty); + connect (this, &MainWindow::aprsClientSendReports, m_aprsClient, &APRSISClient::sendReports); + connect (this, &MainWindow::aprsClientSetLocalStation, m_aprsClient, &APRSISClient::setLocalStation); + connect (this, &MainWindow::aprsClientSetPaused, m_aprsClient, &APRSISClient::setPaused); + connect (this, &MainWindow::aprsClientSetServer, m_aprsClient, &APRSISClient::setServer); + connect (&m_networkThread, &QThread::finished, m_aprsClient, &QObject::deleteLater); + // 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); @@ -814,6 +826,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, displayDialFrequency(); readSettings(); //Restore user's setup params + m_networkThread.start(m_networkThreadPriority); m_audioThread.start (m_audioThreadPriority); m_notificationAudioThread.start(m_notificationAudioThreadPriority); m_decoder.start(m_decoderThreadPriority); @@ -2170,6 +2183,9 @@ MainWindow::~MainWindow() fftwf_export_wisdom_to_filename(cfname); + m_networkThread.quit(); + m_networkThread.wait(); + m_audioThread.quit (); m_audioThread.wait (); @@ -2454,6 +2470,7 @@ void MainWindow::readSettings() m_audioThreadPriority = static_cast (m_settings->value ("Audio/ThreadPriority", QThread::HighPriority).toInt () % 8); m_notificationAudioThreadPriority = static_cast (m_settings->value ("Audio/NotificationThreadPriority", QThread::LowPriority).toInt () % 8); m_decoderThreadPriority = static_cast (m_settings->value ("Audio/DecoderThreadPriority", QThread::HighPriority).toInt () % 8); + m_networkThreadPriority = static_cast (m_settings->value ("Network/NetworkThreadPriority", QThread::LowPriority).toInt () % 8); m_settings->endGroup (); if(m_config.reset_activity()){ @@ -3156,11 +3173,11 @@ void MainWindow::prepareSpotting(){ spotSetLocal(); pskSetLocal(); aprsSetLocal(); - m_aprsClient->setServer(m_config.aprs_server_name(), m_config.aprs_server_port()); - m_aprsClient->setPaused(false); + emit aprsClientSetServer(m_config.aprs_server_name(), m_config.aprs_server_port()); + emit aprsClientSetPaused(false); ui->spotButton->setChecked(true); } else { - m_aprsClient->setPaused(true); + emit aprsClientSetPaused(true); ui->spotButton->setChecked(false); } } @@ -5232,6 +5249,7 @@ void MainWindow::spotCmd(CommandDetail cmd){ // KN4CRD: @APRSIS CMD :EMAIL-2 :email@domain.com booya{1 void MainWindow::spotAprsCmd(CommandDetail cmd){ if(!m_config.spot_to_reporting_networks()) return; + if(!m_config.spot_to_aprs()) return; if(cmd.cmd != " CMD") return; @@ -5240,11 +5258,14 @@ void MainWindow::spotAprsCmd(CommandDetail cmd){ auto by_call = Radio::base_callsign(m_config.my_callsign()); auto from_call = Radio::base_callsign(cmd.from); - m_aprsClient->enqueueThirdParty(by_call, from_call, cmd.text); + // we use a queued signal here so we can process these spots in a network thread + // to prevent blocking the gui/decoder while waiting on TCP + emit aprsClientEnqueueThirdParty(by_call, from_call, cmd.text); } void MainWindow::spotAprsGrid(int offset, int snr, QString callsign, QString grid){ if(!m_config.spot_to_reporting_networks()) return; + if(!m_config.spot_to_aprs()) return; if(grid.length() < 4) return; Frequency frequency = m_freqNominal + offset; @@ -5257,7 +5278,9 @@ void MainWindow::spotAprsGrid(int offset, int snr, QString callsign, QString gri auto by_call = Radio::base_callsign(m_config.my_callsign()); auto from_call = Radio::base_callsign(callsign); - m_aprsClient->enqueueSpot(by_call, from_call, grid, comment); + // we use a queued signal here so we can process these spots in a network thread + // to prevent blocking the gui/decoder while waiting on TCP + emit aprsClientEnqueueSpot(by_call, from_call, grid, comment); } void MainWindow::pskLogReport(QString mode, int offset, int snr, QString callsign, QString grid){ @@ -7887,7 +7910,7 @@ void MainWindow::band_changed (Frequency f) m_bandEdited = false; psk_Reporter->sendReport(); // Upload any queued spots before changing band - m_aprsClient->sendReports(); + emit aprsClientSendReports(); // Upload any queued spots before changing band if (!m_transmitting) monitor (true); if ("FreqCal" == m_mode) @@ -9731,7 +9754,7 @@ void MainWindow::pskSetLocal () void MainWindow::aprsSetLocal () { - m_aprsClient->setLocalStation("APJ8CL", QString::number(APRSISClient::hashCallsign("APJ8CL"))); + emit aprsClientSetLocalStation("APJ8CL", QString::number(APRSISClient::hashCallsign("APJ8CL"))); } void MainWindow::transmitDisplay (bool transmitting) diff --git a/mainwindow.h b/mainwindow.h index 1c7da1e..ae140dc 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -7,6 +7,8 @@ #include #endif #include +#include +#include #include #include #include @@ -434,6 +436,13 @@ private slots: void refreshTextDisplay(); private: + Q_SIGNAL void aprsClientEnqueueSpot(QString by_call, QString from_call, QString grid, QString comment); + Q_SIGNAL void aprsClientEnqueueThirdParty(QString by_call, QString from_call, QString text); + Q_SIGNAL void aprsClientSetServer(QString host, quint16 port); + Q_SIGNAL void aprsClientSetPaused(bool paused); + Q_SIGNAL void aprsClientSetLocalStation(QString mycall, QString passcode); + Q_SIGNAL void aprsClientSendReports(); + Q_SIGNAL void decodedLineReady(QByteArray t); Q_SIGNAL void playNotification(const QString &name); Q_SIGNAL void initializeNotificationAudioOutputStream(const QAudioDeviceInfo &, unsigned, unsigned) const; @@ -505,6 +514,8 @@ private: SoundOutput * m_soundOutput; NotificationAudio * m_notification; + QMutex m_networkThreadMutex; + QThread m_networkThread; QThread m_audioThread; QThread m_notificationAudioThread; Decoder m_decoder; @@ -904,6 +915,7 @@ private: QThread::Priority m_audioThreadPriority; QThread::Priority m_notificationAudioThreadPriority; QThread::Priority m_decoderThreadPriority; + QThread::Priority m_networkThreadPriority; bool m_bandEdited; bool m_splitMode; bool m_monitoring;