| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | // Interface to WSPRnet website
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // by Edson Pereira - PY2SDR
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "wsprnet.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 17:20:28 +00:00
										 |  |  | #include <cmath>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | #include <QTimer>
 | 
					
						
							|  |  |  | #include <QFile>
 | 
					
						
							|  |  |  | #include <QNetworkAccessManager>
 | 
					
						
							|  |  |  | #include <QNetworkRequest>
 | 
					
						
							|  |  |  | #include <QNetworkReply>
 | 
					
						
							|  |  |  | #include <QUrl>
 | 
					
						
							| 
									
										
										
										
											2015-11-09 13:01:18 +00:00
										 |  |  | #include <QDebug>
 | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "moc_wsprnet.cpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   char const * const wsprNetUrl = "http://wsprnet.org/post?"; | 
					
						
							|  |  |  |   // char const * const wsprNetUrl = "http://127.0.0.1/post?";
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  | WSPRNet::WSPRNet(QNetworkAccessManager * manager, QObject *parent) | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  |   : QObject{parent} | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  |   , networkManager {manager} | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  |   , uploadTimer {new QTimer {this}} | 
					
						
							|  |  |  |   , m_urlQueueSize {0} | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkReply(QNetworkReply*))); | 
					
						
							|  |  |  |   connect( uploadTimer, SIGNAL(timeout()), this, SLOT(work())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | 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) | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  |   // check if request was ours
 | 
					
						
							|  |  |  |   if (m_outstandingRequests.removeOne (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
 | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  |     else { | 
					
						
							|  |  |  |       QString serverResponse = reply->readAll(); | 
					
						
							|  |  |  |       if( m_uploadType == 2) { | 
					
						
							|  |  |  |         if (!serverResponse.contains(QRegExp("spot\\(s\\) added"))) { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:28:12 +00:00
										 |  |  |           emit uploadStatus(QString {"Upload Failed: %1"}.arg (serverResponse)); | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  |           urlQueue.clear(); | 
					
						
							|  |  |  |           uploadTimer->stop(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  |       if (urlQueue.isEmpty()) { | 
					
						
							|  |  |  |         emit uploadStatus("done"); | 
					
						
							|  |  |  |         QFile::remove(m_file); | 
					
						
							|  |  |  |         uploadTimer->stop(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  |     qDebug () << QString {"WSPRnet.org %1 outstanding requests"}.arg (m_outstandingRequests.size ()); | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-24 11:41:05 +00:00
										 |  |  |     // delete request object instance on return to the event loop otherwise it is leaked
 | 
					
						
							|  |  |  |     reply->deleteLater (); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | bool WSPRNet::decodeLine(QString const& line, QHash<QString,QString> &query) | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     // 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;; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | QString WSPRNet::urlEncodeSpot(QHash<QString,QString> const& query) | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     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() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-20 12:55:18 +00:00
										 |  |  |   if (!urlQueue.isEmpty()) { | 
					
						
							|  |  |  |     if (QNetworkAccessManager::Accessible != networkManager->networkAccessible ()) { | 
					
						
							|  |  |  |       // try and recover network access for QNAM
 | 
					
						
							|  |  |  |       networkManager->setNetworkAccessible (QNetworkAccessManager::Accessible); | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-20 12:55:18 +00:00
										 |  |  |     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(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-05-27 13:08:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | void WSPRNet::abortOutstandingRequests () { | 
					
						
							|  |  |  |   urlQueue.clear (); | 
					
						
							|  |  |  |   for (auto& request : m_outstandingRequests) { | 
					
						
							|  |  |  |     request->abort (); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-02-20 12:55:18 +00:00
										 |  |  |   m_urlQueueSize = 0; | 
					
						
							| 
									
										
										
										
											2015-06-09 14:30:23 +00:00
										 |  |  | } |