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;