mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-12-24 11:40:31 -05:00
Various WSPR fixes
Make WSPRnet.org spot uploads tolerant of network issues, spots still get discarded for any period that has problems but now uploading resumes on the next period. Ensure that decoded text starts with correct font by not using the base class append method directly. Fixed a major memory leak in the WSPRNet class which was not freeing processed request reply objects. Added some helpful debug prints in WSPRnet.org spot processing. Also tidied up a number of class implementations that were not including he MOC generated code. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5560 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
4b1c3c319f
commit
28b4c31dee
@ -15,6 +15,8 @@
|
|||||||
#include "Bands.hpp"
|
#include "Bands.hpp"
|
||||||
#include "pimpl_impl.hpp"
|
#include "pimpl_impl.hpp"
|
||||||
|
|
||||||
|
#include "moc_FrequencyList.cpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
FrequencyList::FrequencyItems const default_frequency_list =
|
FrequencyList::FrequencyItems const default_frequency_list =
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "moc_Modes.cpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
char const * const mode_names[] =
|
char const * const mode_names[] =
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "moc_PollingTransceiver.cpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
unsigned const polls_to_stabilize {3};
|
unsigned const polls_to_stabilize {3};
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "moc_TransceiverBase.cpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
auto const unexpected = TransceiverBase::tr ("Unexpected rig error");
|
auto const unexpected = TransceiverBase::tr ("Unexpected rig error");
|
||||||
|
@ -47,10 +47,10 @@ void DisplayText::mouseDoubleClickEvent(QMouseEvent *e)
|
|||||||
|
|
||||||
void DisplayText::insertLineSpacer(QString const& line)
|
void DisplayText::insertLineSpacer(QString const& line)
|
||||||
{
|
{
|
||||||
_insertText (line, "#d3d3d3");
|
appendText (line, "#d3d3d3");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayText::_insertText(const QString text, const QString bg)
|
void DisplayText::appendText(QString const& text, QString const& bg)
|
||||||
{
|
{
|
||||||
QString s = "<table border=0 cellspacing=0 width=100%><tr><td bgcolor=\"" +
|
QString s = "<table border=0 cellspacing=0 width=100%><tr><td bgcolor=\"" +
|
||||||
bg + "\">" + text.trimmed ().replace (' ', " ") + "</td></tr></table>";
|
bg + "\">" + text.trimmed ().replace (' ', " ") + "</td></tr></table>";
|
||||||
@ -161,7 +161,7 @@ void DisplayText::displayDecodedText(DecodedText decodedText, QString myCall,
|
|||||||
_appendDXCCWorkedB4(/*mod*/decodedText,bg,logBook,color_CQ,
|
_appendDXCCWorkedB4(/*mod*/decodedText,bg,logBook,color_CQ,
|
||||||
color_DXCC,color_NewCall);
|
color_DXCC,color_NewCall);
|
||||||
|
|
||||||
_insertText(decodedText.string(),bg);
|
appendText(decodedText.string(),bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -176,5 +176,5 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
|
|||||||
QString t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
|
QString t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
|
||||||
" Tx " + t2 + t1 + text; // The position of the 'Tx' is searched for in DecodedText and in MainWindow. Not sure if thats required anymore? VK3ACF
|
" Tx " + t2 + t1 + text; // The position of the 'Tx' is searched for in DecodedText and in MainWindow. Not sure if thats required anymore? VK3ACF
|
||||||
|
|
||||||
_insertText(t,bg);
|
appendText(t,bg);
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,12 @@ signals:
|
|||||||
void selectCallsign(bool shift, bool ctrl);
|
void selectCallsign(bool shift, bool ctrl);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void appendText(QString const& text, QString const& bg = "white");
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _insertText(const QString text, const QString bg);
|
|
||||||
void _appendDXCCWorkedB4(/*mod*/DecodedText& t1, QString &bg, LogBook logBook,
|
void _appendDXCCWorkedB4(/*mod*/DecodedText& t1, QString &bg, LogBook logBook,
|
||||||
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
#include "echograph.h"
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include "echoplot.h"
|
#include "echoplot.h"
|
||||||
#include "echograph.h"
|
|
||||||
#include "ui_echograph.h"
|
#include "ui_echograph.h"
|
||||||
|
#include "moc_echograph.cpp"
|
||||||
|
|
||||||
#define NSMAX2 1366
|
#define NSMAX2 1366
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "StationList.hpp"
|
#include "StationList.hpp"
|
||||||
#include "LiveFrequencyValidator.hpp"
|
#include "LiveFrequencyValidator.hpp"
|
||||||
#include "MessageClient.hpp"
|
#include "MessageClient.hpp"
|
||||||
|
#include "wsprnet.h"
|
||||||
|
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "moc_mainwindow.cpp"
|
#include "moc_mainwindow.cpp"
|
||||||
@ -112,6 +113,7 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
|
|||||||
m_sentFirst73 {false},
|
m_sentFirst73 {false},
|
||||||
m_currentMessageType {-1},
|
m_currentMessageType {-1},
|
||||||
m_lastMessageType {-1},
|
m_lastMessageType {-1},
|
||||||
|
m_uploading {false},
|
||||||
m_nonWSPRTab {-1},
|
m_nonWSPRTab {-1},
|
||||||
m_appDir {QApplication::applicationDirPath ()},
|
m_appDir {QApplication::applicationDirPath ()},
|
||||||
mem_jt9 {shdmem},
|
mem_jt9 {shdmem},
|
||||||
@ -390,7 +392,6 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
|
|||||||
m_nrx=1;
|
m_nrx=1;
|
||||||
m_tx=0;
|
m_tx=0;
|
||||||
m_txNext=false;
|
m_txNext=false;
|
||||||
m_uploading=false;
|
|
||||||
m_grid6=false;
|
m_grid6=false;
|
||||||
m_nseq=0;
|
m_nseq=0;
|
||||||
m_ntr=0;
|
m_ntr=0;
|
||||||
@ -431,7 +432,6 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
|
|||||||
m_wideGraph->setTol(m_tol);
|
m_wideGraph->setTol(m_tol);
|
||||||
m_bShMsgs=false;
|
m_bShMsgs=false;
|
||||||
m_bDopplerTracking0=false;
|
m_bDopplerTracking0=false;
|
||||||
m_uploading=false;
|
|
||||||
m_bTxTime=false;
|
m_bTxTime=false;
|
||||||
m_rxDone=false;
|
m_rxDone=false;
|
||||||
m_bHaveTransmitted=false;
|
m_bHaveTransmitted=false;
|
||||||
@ -2277,7 +2277,7 @@ void MainWindow::startTx2()
|
|||||||
if (m_config.TX_messages ()) {
|
if (m_config.TX_messages ()) {
|
||||||
t = " Transmitting " + m_mode + " ----------------------- " +
|
t = " Transmitting " + m_mode + " ----------------------- " +
|
||||||
m_config.bands ()->find (m_dialFreq);
|
m_config.bands ()->find (m_dialFreq);
|
||||||
ui->decodedTextBrowser->append(t.rightJustified (71, '-'));
|
ui->decodedTextBrowser->appendText(t.rightJustified (71, '-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile f {m_dataDir.absoluteFilePath ("ALL_WSPR.TXT")};
|
QFile f {m_dataDir.absoluteFilePath ("ALL_WSPR.TXT")};
|
||||||
@ -4222,12 +4222,12 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
|
|||||||
QString band;
|
QString band;
|
||||||
Frequency f=1000000.0*rxFields.at(3).toDouble()+0.5;
|
Frequency f=1000000.0*rxFields.at(3).toDouble()+0.5;
|
||||||
band = ' ' + m_config.bands ()->find (f);
|
band = ' ' + m_config.bands ()->find (f);
|
||||||
ui->decodedTextBrowser->append(band.rightJustified (71, '-'));
|
ui->decodedTextBrowser->appendText(band.rightJustified (71, '-'));
|
||||||
m_blankLine = false;
|
m_blankLine = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ui->decodedTextBrowser->append(t);
|
// ui->decodedTextBrowser->appendText(t);
|
||||||
ui->decodedTextBrowser->append(rxLine);
|
ui->decodedTextBrowser->appendText(rxLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4237,7 +4237,8 @@ void MainWindow::uploadSpots()
|
|||||||
if(m_diskData) return;
|
if(m_diskData) return;
|
||||||
if(m_uploading) {
|
if(m_uploading) {
|
||||||
qDebug() << "Previous upload has not completed, spots were lost";
|
qDebug() << "Previous upload has not completed, spots were lost";
|
||||||
return;
|
wsprNet->abortOutstandingRequests ();
|
||||||
|
m_uploading = false;
|
||||||
}
|
}
|
||||||
QString rfreq = QString("%1").arg(0.000001*(m_dialFreqRxWSPR + 1500), 0, 'f', 6);
|
QString rfreq = QString("%1").arg(0.000001*(m_dialFreqRxWSPR + 1500), 0, 'f', 6);
|
||||||
QString tfreq = QString("%1").arg(0.000001*(m_dialFreqRxWSPR +
|
QString tfreq = QString("%1").arg(0.000001*(m_dialFreqRxWSPR +
|
||||||
@ -4255,6 +4256,8 @@ void MainWindow::uploadResponse(QString response)
|
|||||||
m_uploading=false;
|
m_uploading=false;
|
||||||
} else if (response == "Upload Failed") {
|
} else if (response == "Upload Failed") {
|
||||||
m_uploading=false;
|
m_uploading=false;
|
||||||
|
} else {
|
||||||
|
qDebug () << "WSPRnet.org status:" << response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include "Detector.hpp"
|
#include "Detector.hpp"
|
||||||
#include "Modulator.hpp"
|
#include "Modulator.hpp"
|
||||||
#include "decodedtext.h"
|
#include "decodedtext.h"
|
||||||
#include "wsprnet.h"
|
|
||||||
|
|
||||||
#define NUM_JT4_SYMBOLS 206
|
#define NUM_JT4_SYMBOLS 206
|
||||||
#define NUM_JT65_SYMBOLS 126
|
#define NUM_JT65_SYMBOLS 126
|
||||||
@ -64,6 +63,7 @@ class MessageClient;
|
|||||||
class QTime;
|
class QTime;
|
||||||
class WSPRBandHopping;
|
class WSPRBandHopping;
|
||||||
class HelpTextWindow;
|
class HelpTextWindow;
|
||||||
|
class WSPRNet;
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include <QSettings>
|
|
||||||
#include "messageaveraging.h"
|
#include "messageaveraging.h"
|
||||||
|
#include <QSettings>
|
||||||
#include "ui_messageaveraging.h"
|
#include "ui_messageaveraging.h"
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
|
#include "moc_messageaveraging.cpp"
|
||||||
|
|
||||||
MessageAveraging::MessageAveraging(QSettings * settings, QWidget *parent) :
|
MessageAveraging::MessageAveraging(QSettings * settings, QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
|
82
wsprnet.cpp
82
wsprnet.cpp
@ -4,21 +4,34 @@
|
|||||||
|
|
||||||
#include "wsprnet.h"
|
#include "wsprnet.h"
|
||||||
|
|
||||||
WSPRNet::WSPRNet(QObject *parent) :
|
#include <QTimer>
|
||||||
QObject(parent)
|
#include <QFile>
|
||||||
{
|
#include <QNetworkAccessManager>
|
||||||
wsprNetUrl = "http://wsprnet.org/post?";
|
#include <QNetworkRequest>
|
||||||
//wsprNetUrl = "http://127.0.0.1/post.php?";
|
#include <QNetworkReply>
|
||||||
networkManager = new QNetworkAccessManager(this);
|
#include <QUrl>
|
||||||
connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkReply(QNetworkReply*)));
|
|
||||||
|
|
||||||
uploadTimer = new QTimer(this);
|
#include "moc_wsprnet.cpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
char const * const wsprNetUrl = "http://wsprnet.org/post?";
|
||||||
|
// char const * const wsprNetUrl = "http://127.0.0.1/post?";
|
||||||
|
};
|
||||||
|
|
||||||
|
WSPRNet::WSPRNet(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
, networkManager {new QNetworkAccessManager {this}}
|
||||||
|
, uploadTimer {new QTimer {this}}
|
||||||
|
, m_urlQueueSize {0}
|
||||||
|
{
|
||||||
|
connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkReply(QNetworkReply*)));
|
||||||
connect( uploadTimer, SIGNAL(timeout()), this, SLOT(work()));
|
connect( uploadTimer, SIGNAL(timeout()), this, SLOT(work()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSPRNet::upload(QString call, QString grid, QString rfreq, QString tfreq,
|
void WSPRNet::upload(QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
|
||||||
QString mode, QString tpct, QString dbm, QString version,
|
QString const& mode, QString const& tpct, QString const& dbm, QString const& version,
|
||||||
QString fileName)
|
QString const& fileName)
|
||||||
{
|
{
|
||||||
m_call = call;
|
m_call = call;
|
||||||
m_grid = grid;
|
m_grid = grid;
|
||||||
@ -58,23 +71,36 @@ void WSPRNet::upload(QString call, QString grid, QString rfreq, QString tfreq,
|
|||||||
|
|
||||||
void WSPRNet::networkReply(QNetworkReply *reply)
|
void WSPRNet::networkReply(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
|
if (QNetworkReply::NoError != reply->error ()) {
|
||||||
|
Q_EMIT uploadStatus (QString {"Error: %1"}.arg (reply->error ()));
|
||||||
|
// not clearing queue or halting queuing as it may be a transient
|
||||||
|
// one off request error
|
||||||
|
}
|
||||||
|
else {
|
||||||
QString serverResponse = reply->readAll();
|
QString serverResponse = reply->readAll();
|
||||||
if( m_uploadType == 2) {
|
if( m_uploadType == 2) {
|
||||||
if (!serverResponse.contains(QRegExp("spot\\(s\\) added"))) {
|
if (!serverResponse.contains(QRegExp("spot\\(s\\) added"))) {
|
||||||
emit uploadStatus("Upload Failed");
|
emit uploadStatus("Upload Failed");
|
||||||
urlQueue.clear();
|
urlQueue.clear();
|
||||||
uploadTimer->stop();
|
uploadTimer->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urlQueue.isEmpty()) {
|
if (urlQueue.isEmpty()) {
|
||||||
emit uploadStatus("done");
|
emit uploadStatus("done");
|
||||||
QFile::remove(m_file);
|
QFile::remove(m_file);
|
||||||
uploadTimer->stop();
|
uploadTimer->stop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_outstandingRequests.removeOne (reply);
|
||||||
|
qDebug () << QString {"WSPRnet.org %1 outstanding requests"}.arg (m_outstandingRequests.size ());
|
||||||
|
|
||||||
|
// delete request object instance on return to the event loop otherwise it is leaked
|
||||||
|
reply->deleteLater ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WSPRNet::decodeLine(QString line, QHash<QString,QString> &query)
|
bool WSPRNet::decodeLine(QString const& line, QHash<QString,QString> &query)
|
||||||
{
|
{
|
||||||
// 130223 2256 7 -21 -0.3 14.097090 DU1MGA PK04 37 0 40 0
|
// 130223 2256 7 -21 -0.3 14.097090 DU1MGA PK04 37 0 40 0
|
||||||
// Date Time Sync dBm DT Freq Msg
|
// Date Time Sync dBm DT Freq Msg
|
||||||
@ -152,7 +178,7 @@ QString WSPRNet::urlEncodeNoSpot()
|
|||||||
return queryString;;
|
return queryString;;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WSPRNet::urlEncodeSpot(QHash<QString,QString> query)
|
QString WSPRNet::urlEncodeSpot(QHash<QString,QString> const& query)
|
||||||
{
|
{
|
||||||
QString queryString;
|
QString queryString;
|
||||||
queryString += "function=" + query["function"] + "&";
|
queryString += "function=" + query["function"] + "&";
|
||||||
@ -179,14 +205,16 @@ void WSPRNet::work()
|
|||||||
if (!urlQueue.isEmpty()) {
|
if (!urlQueue.isEmpty()) {
|
||||||
QUrl url(urlQueue.dequeue());
|
QUrl url(urlQueue.dequeue());
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
networkManager->get(request);
|
m_outstandingRequests << networkManager->get(request);
|
||||||
QString status = "Uploading Spot " + QString::number(m_urlQueueSize - urlQueue.size()) +
|
emit uploadStatus(QString {"Uploading Spot %1/%2"}.arg (m_urlQueueSize - urlQueue.size()).arg (m_urlQueueSize));
|
||||||
"/"+ QString::number(m_urlQueueSize);
|
|
||||||
emit uploadStatus(status);
|
|
||||||
} else {
|
} else {
|
||||||
uploadTimer->stop();
|
uploadTimer->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WSPRNet::abortOutstandingRequests () {
|
||||||
|
urlQueue.clear ();
|
||||||
|
for (auto& request : m_outstandingRequests) {
|
||||||
|
request->abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
27
wsprnet.h
27
wsprnet.h
@ -2,17 +2,25 @@
|
|||||||
#define WSPRNET_H
|
#define WSPRNET_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QtNetwork>
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QTimer;
|
||||||
|
class QNetworkReply;
|
||||||
|
|
||||||
class WSPRNet : public QObject
|
class WSPRNet : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WSPRNet(QObject *parent = 0);
|
explicit WSPRNet(QObject *parent = nullptr);
|
||||||
void upload(QString call, QString grid, QString rfreq, QString tfreq,
|
void upload(QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
|
||||||
QString mode, QString tpct, QString dbm, QString version,
|
QString const& mode, QString const& tpct, QString const& dbm, QString const& version,
|
||||||
QString fileName);
|
QString const& fileName);
|
||||||
static bool decodeLine(QString line, QHash<QString,QString> &query);
|
static bool decodeLine(QString const& line, QHash<QString,QString> &query);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void uploadStatus(QString);
|
void uploadStatus(QString);
|
||||||
@ -20,10 +28,11 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
void networkReply(QNetworkReply *);
|
void networkReply(QNetworkReply *);
|
||||||
void work();
|
void work();
|
||||||
|
void abortOutstandingRequests ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkAccessManager *networkManager;
|
QNetworkAccessManager *networkManager;
|
||||||
QString wsprNetUrl;
|
QList<QNetworkReply *> m_outstandingRequests;
|
||||||
QString m_call, m_grid, m_rfreq, m_tfreq, m_mode, m_tpct, m_dbm, m_vers, m_file;
|
QString m_call, m_grid, m_rfreq, m_tfreq, m_mode, m_tpct, m_dbm, m_vers, m_file;
|
||||||
QQueue<QString> urlQueue;
|
QQueue<QString> urlQueue;
|
||||||
QTimer *uploadTimer;
|
QTimer *uploadTimer;
|
||||||
@ -31,7 +40,7 @@ private:
|
|||||||
int m_uploadType;
|
int m_uploadType;
|
||||||
|
|
||||||
QString urlEncodeNoSpot();
|
QString urlEncodeNoSpot();
|
||||||
QString urlEncodeSpot(QHash<QString,QString> spot);
|
QString urlEncodeSpot(QHash<QString,QString> const& spot);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WSPRNET_H
|
#endif // WSPRNET_H
|
||||||
|
Loading…
Reference in New Issue
Block a user