mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-30 20:40:28 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			233 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Interface to WSPRnet website
 | |
| //
 | |
| // by Edson Pereira - PY2SDR
 | |
| 
 | |
| #include "wsprnet.h"
 | |
| 
 | |
| #include <cmath>
 | |
| 
 | |
| #include <QTimer>
 | |
| #include <QFile>
 | |
| #include <QNetworkAccessManager>
 | |
| #include <QNetworkRequest>
 | |
| #include <QNetworkReply>
 | |
| #include <QUrl>
 | |
| #include <QDebug>
 | |
| 
 | |
| #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(QNetworkAccessManager * manager, QObject *parent)
 | |
|   : QObject{parent}
 | |
|   , networkManager {manager}
 | |
|   , 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)
 | |
| {
 | |
|   // 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
 | |
|     }
 | |
|     else {
 | |
|       QString serverResponse = reply->readAll();
 | |
|       if( m_uploadType == 2) {
 | |
|         if (!serverResponse.contains(QRegExp("spot\\(s\\) added"))) {
 | |
|           emit uploadStatus(QString {"Upload Failed: %1"}.arg (serverResponse));
 | |
|           urlQueue.clear();
 | |
|           uploadTimer->stop();
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (urlQueue.isEmpty()) {
 | |
|         emit uploadStatus("done");
 | |
|         QFile::remove(m_file);
 | |
|         uploadTimer->stop();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     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") 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") queryString += "&mode=2";
 | |
|     if(m_mode=="WSPR-15") queryString += "&mode=15";
 | |
|     return queryString;
 | |
| }
 | |
| 
 | |
| void WSPRNet::work()
 | |
| {
 | |
|   if (!urlQueue.isEmpty()) {
 | |
| #if QT_VERSION < QT_VERSION_CHECK (5, 15, 0)
 | |
|     if (QNetworkAccessManager::Accessible != networkManager->networkAccessible ()) {
 | |
|       // try and recover network access for QNAM
 | |
|       networkManager->setNetworkAccessible (QNetworkAccessManager::Accessible);
 | |
|     }
 | |
| #endif
 | |
|     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 ();
 | |
|   }
 | |
|   m_urlQueueSize = 0;
 | |
| }
 |