diff --git a/APRSISClient.cpp b/APRSISClient.cpp index 16139a5..4934e2e 100644 --- a/APRSISClient.cpp +++ b/APRSISClient.cpp @@ -206,28 +206,31 @@ QString APRSISClient::replaceCallsignSuffixWithSSID(QString call, QString base){ return call; } -void APRSISClient::enqueueSpot(QString theircall, QString grid, QString comment){ - if(m_localCall.isEmpty()) return; - - auto geo = APRSISClient::grid2aprs(grid); - auto spotFrame = QString("%1>APRS,%2,TCPIP*:=%3/%4nJS8 %5\n"); - spotFrame = spotFrame.arg(theircall); - spotFrame = spotFrame.arg(stripSSID(m_localCall)); - spotFrame = spotFrame.arg(geo.first); - spotFrame = spotFrame.arg(geo.second); - spotFrame = spotFrame.arg(comment.left(43)); - enqueueRaw(spotFrame); -} - -void APRSISClient::enqueueThirdParty(QString theircall, QString payload){ +void APRSISClient::enqueueSpot(QString by_call, QString from_call, QString grid, QString comment){ if(!isPasscodeValid()){ return; } - auto frame = QString("%1>APRS,%2,TCPIP*:%3\n"); - frame = frame.arg(theircall); - frame = frame.arg(stripSSID(m_localCall)); - frame = frame.arg(payload); + auto geo = APRSISClient::grid2aprs(grid); + auto spotFrame = QString("%1>APJ8CL,qAS,%2:=%3/%4G#JS8 %5\n"); + spotFrame = spotFrame.arg(from_call); + spotFrame = spotFrame.arg(by_call); + spotFrame = spotFrame.arg(geo.first); + spotFrame = spotFrame.arg(geo.second); + spotFrame = spotFrame.arg(comment.left(42)); + enqueueRaw(spotFrame); +} + +void APRSISClient::enqueueThirdParty(QString by_call, QString from_call, QString text){ + if(!isPasscodeValid()){ + return; + } + + auto frame = QString("%1>APJ8CL,qAS,%2:%3\n"); + frame = frame.arg(from_call); + frame = frame.arg(by_call); + frame = frame.arg(text); + enqueueRaw(frame); } diff --git a/APRSISClient.h b/APRSISClient.h index 2fb1885..c7d30c8 100644 --- a/APRSISClient.h +++ b/APRSISClient.h @@ -35,16 +35,15 @@ public: m_paused = paused; } - void setLocalStation(QString mycall, QString mygrid, QString passcode){ + void setLocalStation(QString mycall, QString passcode){ m_localCall = mycall; - m_localGrid = mygrid; m_localPasscode = passcode; } bool isPasscodeValid(){ return m_localPasscode == QString::number(hashCallsign(m_localCall)); } - void enqueueSpot(QString theircall, QString grid, QString comment); - void enqueueThirdParty(QString theircall, QString payload); + 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); @@ -58,7 +57,6 @@ public slots: private: QString m_localCall; - QString m_localGrid; QString m_localPasscode; QQueue> m_frameQueue; diff --git a/Configuration.cpp b/Configuration.cpp index 1da456c..1db40ee 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -678,7 +678,6 @@ private: QString opCall_; QString ptt_command_; QString aprs_server_name_; - QString aprs_passcode_; port_type aprs_server_port_; QString udp_server_name_; @@ -859,7 +858,6 @@ QString Configuration::opCall() const {return m_->opCall_;} QString Configuration::ptt_command() const { return m_->ptt_command_.trimmed();} QString Configuration::aprs_server_name () const {return m_->aprs_server_name_;} auto Configuration::aprs_server_port () const -> port_type {return m_->aprs_server_port_;} -QString Configuration::aprs_passcode() const { return m_->aprs_passcode_; } QString Configuration::udp_server_name () const {return m_->udp_server_name_;} auto Configuration::udp_server_port () const -> port_type {return m_->udp_server_port_;} bool Configuration::accept_udp_requests () const {return m_->accept_udp_requests_;} @@ -1609,7 +1607,6 @@ void Configuration::impl::initialize_models () ui_->ptt_command_line_edit->setText(ptt_command_); ui_->aprs_server_line_edit->setText (aprs_server_name_); ui_->aprs_server_port_spin_box->setValue (aprs_server_port_); - ui_->aprs_passcode_line_edit->setText(aprs_passcode_); ui_->udp_server_line_edit->setText (udp_server_name_); ui_->udp_server_port_spin_box->setValue (udp_server_port_); ui_->accept_udp_requests_check_box->setChecked (accept_udp_requests_); @@ -2060,7 +2057,6 @@ void Configuration::impl::read_settings () ptt_command_ = settings_->value("PTTCommand", "").toString(); aprs_server_name_ = settings_->value ("aprsServer", "rotate.aprs2.net").toString (); aprs_server_port_ = settings_->value ("aprsServerPort", 14580).toUInt (); - aprs_passcode_ = settings_->value ("aprsPasscode", "").toString(); udp_server_name_ = settings_->value ("UDPServer", "127.0.0.1").toString (); udp_server_port_ = settings_->value ("UDPServerPort", 2242).toUInt (); n3fjp_server_name_ = settings_->value ("N3FJPServer", "127.0.0.1").toString (); @@ -2246,7 +2242,6 @@ void Configuration::impl::write_settings () settings_->setValue ("PTTCommand", ptt_command_); settings_->setValue ("aprsServer", aprs_server_name_); settings_->setValue ("aprsServerPort", aprs_server_port_); - settings_->setValue ("aprsPasscode", aprs_passcode_); settings_->setValue ("UDPServer", udp_server_name_); settings_->setValue ("UDPServerPort", udp_server_port_); settings_->setValue ("N3FJPServer", n3fjp_server_name_); @@ -2861,7 +2856,6 @@ void Configuration::impl::accept () ptt_command_ = ui_->ptt_command_line_edit->text(); aprs_server_name_ = ui_->aprs_server_line_edit->text(); aprs_server_port_ = ui_->aprs_server_port_spin_box->value(); - aprs_passcode_ = ui_->aprs_passcode_line_edit->text(); auto newUdpEnabled = ui_->udpEnable->isChecked(); auto new_server = ui_->udp_server_line_edit->text (); diff --git a/Configuration.hpp b/Configuration.hpp index bac47b5..98cc4c4 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -185,7 +185,6 @@ public: QString ptt_command() const; QString aprs_server_name () const; port_type aprs_server_port () const; - QString aprs_passcode () const; QString udp_server_name () const; port_type udp_server_port () const; QString n1mm_server_name () const; diff --git a/Configuration.ui b/Configuration.ui index d38f1d5..cbb8c19 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -315,7 +315,7 @@ 0 0 - 724 + 615 537 @@ -837,8 +837,8 @@ text message. 0 0 - 738 - 461 + 674 + 360 @@ -876,7 +876,9 @@ text message. - false + + false + Send SNR report when acknowledging heartbeats @@ -2366,9 +2368,9 @@ both here. 0 - 0 + -60 746 - 567 + 682 @@ -2616,7 +2618,7 @@ This is used for reverse ping analysis which is very useful for assessing propagation and system performance. - Enable spotting to reporting networks (JS8NET, PSKReporter, etc) + Enable spotting to reporting networks (JS8NET, APRSIS, PSKReporter, etc) true @@ -2626,6 +2628,77 @@ for assessing propagation and system performance. + + + + APRSIS Spotting + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + APRS Server: + + + udp_server_line_edit + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Optional hostname of APRS server to send spots to.</p><p>Formats:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 multicast group address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 multicast group address</li></ul><p>Clearing this field will disable the spotting to APRS.</p></body></html> + + + Qt::ImhDigitsOnly + + + rotate.aprs2.net + + + + + + + APRS Server Port: + + + udp_server_port_spin_box + + + + + + + <html><head/><body><p>Enter the service port number of the APRS server that should receive updates. If this is zero no updates will be broadcast.</p></body></html> + + + 0 + + + 65534 + + + 14580 + + + + + + + + @@ -2736,9 +2809,6 @@ for assessing propagation and system performance. 0 - - false - 0 @@ -2755,81 +2825,6 @@ for assessing propagation and system performance. 0 - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - APRS Server: - - - udp_server_line_edit - - - - - - - - 0 - 0 - - - - <html><head/><body><p>Optional hostname of APRS server to send spots to.</p><p>Formats:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 multicast group address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 multicast group address</li></ul><p>Clearing this field will disable the spotting to APRS.</p></body></html> - - - Qt::ImhDigitsOnly - - - rotate.aprs2.net - - - - - - - APRS Server Port: - - - udp_server_port_spin_box - - - - - - - <html><head/><body><p>Enter the service port number of the APRS server that should receive updates. If this is zero no updates will be broadcast.</p></body></html> - - - 0 - - - 65534 - - - 14580 - - - - - - - <html><head/><body><p>APRS Server Passcode for Sending APRS Packets</p></body></html> - - - APRS Passcode: - - - - - - - - @@ -4516,7 +4511,6 @@ soundcard changes psk_reporter_check_box aprs_server_line_edit aprs_server_port_spin_box - aprs_passcode_line_edit enable_n3fjp_broadcast_check_box n3fjp_server_name_line_edit n3fjp_server_port_spin_box diff --git a/js8call.pro b/js8call.pro index ace9de8..9b9d995 100644 --- a/js8call.pro +++ b/js8call.pro @@ -91,7 +91,8 @@ SOURCES += \ WaveUtils.cpp \ ProcessThread.cpp \ DecoderThread.cpp \ - Decoder.cpp + Decoder.cpp \ + APRSISClient.cpp HEADERS += qt_helpers.hpp \ pimpl_h.hpp pimpl_impl.hpp \ @@ -133,7 +134,8 @@ HEADERS += qt_helpers.hpp \ WaveUtils.h \ ProcessThread.h \ DecoderThread.h \ - Decoder.h + Decoder.h \ + APRSISClient.h INCLUDEPATH += qmake_only diff --git a/mainwindow.cpp b/mainwindow.cpp index 27ddce2..1e7b279 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -437,6 +437,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, this}}, m_n3fjpClient { new TCPClient{this}}, m_spotClient { new SpotClient{m_messageClient, this}}, + m_aprsClient {new APRSISClient{"rotate.aprs2.net", 14580, this}}, psk_Reporter {new PSK_Reporter {m_messageClient, this}}, m_i3bit {0}, m_manual {&m_network_manager}, @@ -3154,8 +3155,12 @@ void MainWindow::prepareSpotting(){ if(m_config.spot_to_reporting_networks ()){ spotSetLocal(); pskSetLocal(); + aprsSetLocal(); + m_aprsClient->setServer(m_config.aprs_server_name(), m_config.aprs_server_port()); + m_aprsClient->setPaused(false); ui->spotButton->setChecked(true); } else { + m_aprsClient->setPaused(true); ui->spotButton->setChecked(false); } } @@ -5224,6 +5229,37 @@ void MainWindow::spotCmd(CommandDetail cmd){ m_spotClient->enqueueCmd(cmdStr, cmd.from, cmd.to, cmd.relayPath, cmd.text, cmd.grid, cmd.extra, cmd.submode, m_freqNominal + cmd.freq, cmd.snr); } +// KN4CRD: @APRSIS CMD :EMAIL-2 :email@domain.com booya{1 +void MainWindow::spotAprsCmd(CommandDetail cmd){ + if(!m_config.spot_to_reporting_networks()) return; + + if(cmd.cmd != " CMD") return; + + qDebug() << "APRSISClient Enqueueing Third Party Text" << cmd.from << cmd.text; + + 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); +} + +void MainWindow::spotAprsGrid(int offset, int snr, QString callsign, QString grid){ + if(!m_config.spot_to_reporting_networks()) return; + if(grid.length() < 4) return; + + Frequency frequency = m_freqNominal + offset; + + auto comment = QString("%1MHz %2dB").arg(Radio::frequency_MHz_string(frequency)).arg(Varicode::formatSNR(snr)); + if(callsign.contains("/")){ + comment = QString("%1 %2").arg(callsign).arg(comment); + } + + 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); +} + void MainWindow::pskLogReport(QString mode, int offset, int snr, QString callsign, QString grid){ if(!m_config.spot_to_reporting_networks()) return; @@ -7851,6 +7887,8 @@ void MainWindow::band_changed (Frequency f) m_bandEdited = false; psk_Reporter->sendReport(); // Upload any queued spots before changing band + m_aprsClient->sendReports(); + if (!m_transmitting) monitor (true); if ("FreqCal" == m_mode) { @@ -9526,6 +9564,7 @@ void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const& if (m_config.spot_to_reporting_networks ()) { spotSetLocal(); pskSetLocal(); + aprsSetLocal(); } statusChanged(); m_wideGraph->setDialFreq(m_freqNominal / 1.e6); @@ -9690,6 +9729,11 @@ void MainWindow::pskSetLocal () psk_Reporter->setLocalStation(m_config.my_callsign (), m_config.my_grid (), info, QString {"JS8Call v" + version() }.simplified ()); } +void MainWindow::aprsSetLocal () +{ + m_aprsClient->setLocalStation("APJ8CL", QString::number(APRSISClient::hashCallsign("APJ8CL"))); +} + void MainWindow::transmitDisplay (bool transmitting) { ui->monitorTxButton->setChecked(transmitting); @@ -10839,6 +10883,11 @@ void MainWindow::processCommandActivity() { cd.tdrift = d.tdrift; cd.submode = d.submode; + // PROCESS GRID SPOTS TO APRSIS FOR EVERYONE + if(d.to == "@APRSIS"){ + spotAprsGrid(cd.freq, cd.snr, cd.call, cd.grid); + } + logCallActivity(cd, true); } } @@ -10848,6 +10897,11 @@ void MainWindow::processCommandActivity() { spotCmd(d); } + // PROCESS @APRSIS CMD SPOTS FOR EVERYONE + if (d.to == "@APRSIS"){ + spotAprsCmd(d); + } + // PREPARE CMD TEXT STRING QStringList textList = { QString("%1: %2%3").arg(d.from).arg(d.to).arg(d.cmd) diff --git a/mainwindow.h b/mainwindow.h index dd02320..1c7da1e 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -46,6 +46,7 @@ #include "MessageClient.hpp" #include "TCPClient.h" #include "SpotClient.h" +#include "APRSISClient.h" #include "keyeater.h" #include "NotificationAudio.h" #include "ProcessThread.h" @@ -922,6 +923,7 @@ private: TCPClient * m_n3fjpClient; PSK_Reporter *psk_Reporter; SpotClient *m_spotClient; + APRSISClient *m_aprsClient; DisplayManual m_manual; QHash m_pwrBandTxMemory; // Remembers power level by band QHash m_pwrBandTuneMemory; // Remembers power level by band for tuning @@ -955,9 +957,12 @@ private: void rigFailure (QString const& reason); void spotSetLocal(); void pskSetLocal (); + void aprsSetLocal (); void spotReport(int submode, int offset, int snr, QString callsign, QString grid); void spotCmd(CommandDetail cmd); + void spotAprsCmd(CommandDetail cmd); void pskLogReport(QString mode, int offset, int snr, QString callsign, QString grid); + void spotAprsGrid(int offset, int snr, QString callsign, QString grid); Radio::Frequency dialFrequency(); void setSubmode(int submode); int submodeNameToSubmode(QString speed);