WSJT-X/wsprnet.cpp
Bill Somerville 0d8772f25a 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
2015-06-09 14:30:23 +00:00

221 lines
6.7 KiB
C++

// Interface to WSPRnet website
//
// by Edson Pereira - PY2SDR
#include "wsprnet.h"
#include <QTimer>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#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()));
}
void WSPRNet::upload(QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
QString const& mode, QString const& tpct, QString const& dbm, QString const& version,
QString const& fileName)
{
m_call = call;
m_grid = grid;
m_rfreq = rfreq;
m_tfreq = tfreq;
m_mode = mode;
m_tpct = tpct;
m_dbm = dbm;
m_vers = version;
m_file = fileName;
// Open the wsprd.out file
QFile wsprdOutFile(fileName);
if (!wsprdOutFile.open(QIODevice::ReadOnly | QIODevice::Text) ||
wsprdOutFile.size() == 0) {
urlQueue.enqueue( wsprNetUrl + urlEncodeNoSpot());
m_uploadType = 1;
uploadTimer->start(200);
return;
}
// Read the contents
while (!wsprdOutFile.atEnd()) {
QHash<QString,QString> query;
if ( decodeLine(wsprdOutFile.readLine(), query) ) {
// Prevent reporting data ouside of the current frequency band
float f = fabs(m_rfreq.toFloat() - query["tqrg"].toFloat());
if (f < 0.0002) {
urlQueue.enqueue( wsprNetUrl + urlEncodeSpot(query));
m_uploadType = 2;
}
}
}
m_urlQueueSize = urlQueue.size();
uploadTimer->start(200);
}
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();
if( m_uploadType == 2) {
if (!serverResponse.contains(QRegExp("spot\\(s\\) added"))) {
emit uploadStatus("Upload Failed");
urlQueue.clear();
uploadTimer->stop();
}
}
if (urlQueue.isEmpty()) {
emit uploadStatus("done");
QFile::remove(m_file);
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 const& line, QHash<QString,QString> &query)
{
// 130223 2256 7 -21 -0.3 14.097090 DU1MGA PK04 37 0 40 0
// Date Time Sync dBm DT Freq Msg
// 1 2 3 4 5 6 -------7------ 8 9 10
QRegExp rx("^(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+([+-]?\\d+)\\s+([+-]?\\d+\\.\\d+)\\s+(\\d+\\.\\d+)\\s+(.*)\\s+([+-]?\\d+)\\s+([+-]?\\d+)\\s+([+-]?\\d+)");
if (rx.indexIn(line) != -1) {
int msgType = 0;
QString msg = rx.cap(7);
msg.remove(QRegExp("\\s+$"));
msg.remove(QRegExp("^\\s+"));
QString call, grid, dbm;
QRegExp msgRx;
// Check for Message Type 1
msgRx.setPattern("^([A-Z0-9]{3,6})\\s+([A-Z]{2}\\d{2})\\s+(\\d+)");
if (msgRx.indexIn(msg) != -1) {
msgType = 1;
call = msgRx.cap(1);
grid = msgRx.cap(2);
dbm = msgRx.cap(3);
}
// Check for Message Type 2
msgRx.setPattern("^([A-Z0-9/]+)\\s+(\\d+)");
if (msgRx.indexIn(msg) != -1) {
msgType = 2;
call = msgRx.cap(1);
grid = "";
dbm = msgRx.cap(2);
}
// Check for Message Type 3
msgRx.setPattern("^<([A-Z0-9/]+)>\\s+([A-Z]{2}\\d{2}[A-Z]{2})\\s+(\\d+)");
if (msgRx.indexIn(msg) != -1) {
msgType = 3;
call = msgRx.cap(1);
grid = msgRx.cap(2);
dbm = msgRx.cap(3);
}
// Unknown message format
if (!msgType) {
return false;
}
query["function"] = "wspr";
query["date"] = rx.cap(1);
query["time"] = rx.cap(2);
query["sig"] = rx.cap(4);
query["dt"] = rx.cap(5);
query["drift"] = rx.cap(8);
query["tqrg"] = rx.cap(6);
query["tcall"] = call;
query["tgrid"] = grid;
query["dbm"] = dbm;
} else {
return false;
}
return true;
}
QString WSPRNet::urlEncodeNoSpot()
{
QString queryString;
queryString += "function=wsprstat&";
queryString += "rcall=" + m_call + "&";
queryString += "rgrid=" + m_grid + "&";
queryString += "rqrg=" + m_rfreq + "&";
queryString += "tpct=" + m_tpct + "&";
queryString += "tqrg=" + m_tfreq + "&";
queryString += "dbm=" + m_dbm + "&";
queryString += "version=" + m_vers;
if(m_mode=="WSPR-2") queryString += "&mode=2";
if(m_mode=="WSPR-15") queryString += "&mode=15";
return queryString;;
}
QString WSPRNet::urlEncodeSpot(QHash<QString,QString> const& query)
{
QString queryString;
queryString += "function=" + query["function"] + "&";
queryString += "rcall=" + m_call + "&";
queryString += "rgrid=" + m_grid + "&";
queryString += "rqrg=" + m_rfreq + "&";
queryString += "date=" + query["date"] + "&";
queryString += "time=" + query["time"] + "&";
queryString += "sig=" + query["sig"] + "&";
queryString += "dt=" + query["dt"] + "&";
queryString += "drift=" + query["drift"] + "&";
queryString += "tqrg=" + query["tqrg"] + "&";
queryString += "tcall=" + query["tcall"] + "&";
queryString += "tgrid=" + query["tgrid"] + "&";
queryString += "dbm=" + query["dbm"] + "&";
queryString += "version=" + m_vers;
if(m_mode=="WSPR-2") queryString += "&mode=2";
if(m_mode=="WSPR-15") queryString += "&mode=15";
return queryString;
}
void WSPRNet::work()
{
if (!urlQueue.isEmpty()) {
QUrl url(urlQueue.dequeue());
QNetworkRequest request(url);
m_outstandingRequests << networkManager->get(request);
emit uploadStatus(QString {"Uploading Spot %1/%2"}.arg (m_urlQueueSize - urlQueue.size()).arg (m_urlQueueSize));
} else {
uploadTimer->stop();
}
}
void WSPRNet::abortOutstandingRequests () {
urlQueue.clear ();
for (auto& request : m_outstandingRequests) {
request->abort ();
}
}