| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							| 
									
										
										
										
											2019-01-23 00:44:13 +01:00
										 |  |  | // Copyright (C) 2018-2019 Edouard Griffiths, F4EXB                              //
 | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // This program is free software; you can redistribute it and/or modify          //
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by          //
 | 
					
						
							|  |  |  | // the Free Software Foundation as version 3 of the License, or                  //
 | 
					
						
							| 
									
										
										
										
											2019-04-11 06:39:30 +02:00
										 |  |  | // (at your option) any later version.                                           //
 | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,               //
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
					
						
							|  |  |  | // GNU General Public License V3 for more details.                               //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License             //
 | 
					
						
							|  |  |  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-02 22:58:42 +01:00
										 |  |  | #include <channel/remotedatablock.h>
 | 
					
						
							|  |  |  | #include <channel/remotedataqueue.h>
 | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  | #include <QThread>
 | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  | #include "cm256cc/cm256.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | #include "remotesourceworker.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | MESSAGE_CLASS_DEFINITION(RemoteSourceWorker::MsgDataBind, Message) | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | RemoteSourceWorker::RemoteSourceWorker(RemoteDataQueue *dataQueue, QObject* parent) : | 
					
						
							|  |  |  |     QObject(parent), | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |     m_running(false), | 
					
						
							|  |  |  |     m_dataQueue(dataQueue), | 
					
						
							|  |  |  |     m_address(QHostAddress::LocalHost), | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |     m_socket(this), | 
					
						
							|  |  |  |     m_mutex(QMutex::Recursive), | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     m_sampleRate(0), | 
					
						
							|  |  |  |     m_udpReadBytes(0) | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     m_udpBuf = new char[RemoteUdpSize]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::fill(m_dataFrames, m_dataFrames+4, (RemoteDataFrame *) 0); | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |     connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |     connect(&m_socket, SIGNAL(readyRead()),this, SLOT(recv())); | 
					
						
							|  |  |  | #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
 | 
					
						
							| 
									
										
										
										
											2021-12-07 15:45:19 +01:00
										 |  |  |     connect(&m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &RemoteSourceWorker::errorOccurred); | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  |     connect(&m_socket, &QAbstractSocket::errorOccurred, this, &RemoteSourceWorker::errorOccurred); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | RemoteSourceWorker::~RemoteSourceWorker() | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |     qDebug("RemoteSourceWorker::~RemoteSourceWorker"); | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | void RemoteSourceWorker::dataBind(const QString& address, uint16_t port) | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     MsgDataBind *msg = MsgDataBind::create(address, port); | 
					
						
							|  |  |  |     m_inputMessageQueue.push(msg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  | bool RemoteSourceWorker::startWork() | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |     qDebug("RemoteSourceWorker::startWork"); | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |     QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  |     m_socket.setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, getDataSocketBufferSize(m_sampleRate)); | 
					
						
							|  |  |  |     connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); | 
					
						
							|  |  |  |     connect(thread(), SIGNAL(started()), this, SLOT(started())); | 
					
						
							|  |  |  |     connect(thread(), SIGNAL(finished()), this, SLOT(finished())); | 
					
						
							|  |  |  |     m_running = true; | 
					
						
							|  |  |  |     return m_running; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceWorker::started() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     disconnect(thread(), SIGNAL(started()), this, SLOT(started())); | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | void RemoteSourceWorker::stopWork() | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |     qDebug("RemoteSourceWorker::stopWork"); | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |     QMutexLocker mutexLocker(&m_mutex); | 
					
						
							|  |  |  |     disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceWorker::finished() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Close any existing connection
 | 
					
						
							|  |  |  |     if (m_socket.isOpen()) { | 
					
						
							|  |  |  |         m_socket.close(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |     m_running = false; | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |     disconnect(thread(), SIGNAL(finished()), this, SLOT(finished())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceWorker::errorOccurred(QAbstractSocket::SocketError socketError) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qWarning() << "RemoteSourceWorker::errorOccurred: " << socketError; | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | void RemoteSourceWorker::handleInputMessages() | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     Message* message; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-10 23:40:28 +01:00
										 |  |  |     while ((message = m_inputMessageQueue.pop()) != nullptr) | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |         if (MsgDataBind::match(*message)) | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |             QMutexLocker mutexLocker(&m_mutex); | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |             MsgDataBind* notif = (MsgDataBind*) message; | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |             qDebug("RemoteSourceWorker::handleInputMessages: MsgDataBind: %s:%d", qPrintable(notif->getAddress().toString()), notif->getPort()); | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             disconnect(&m_socket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); | 
					
						
							| 
									
										
										
										
											2021-12-10 23:40:28 +01:00
										 |  |  |             m_socket.abort(); | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |             m_socket.bind(notif->getAddress(), notif->getPort()); | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             connect(&m_socket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  | void RemoteSourceWorker::dataReadyRead() | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     m_udpReadBytes = 0; | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  | 	while (m_socket.hasPendingDatagrams()) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		qint64 pendingDataSize = m_socket.pendingDatagramSize(); | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |         QHostAddress sender; | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  | 		m_udpReadBytes += m_socket.readDatagram(&m_udpBuf[m_udpReadBytes], pendingDataSize, &sender, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (m_udpReadBytes == RemoteUdpSize) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  | 		    processData(); | 
					
						
							|  |  |  | 		    m_udpReadBytes = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceWorker::processData() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RemoteSuperBlock *superBlock = (RemoteSuperBlock *) m_udpBuf; | 
					
						
							|  |  |  |     unsigned int dataBlockIndex = superBlock->m_header.m_frameIndex % m_nbDataFrames; | 
					
						
							|  |  |  |     int blockIndex = superBlock->m_header.m_blockIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (blockIndex == 0) // first block with meta data
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         const RemoteMetaDataFEC *metaData = (const RemoteMetaDataFEC *) &superBlock->m_protectedBlock; | 
					
						
							|  |  |  |         uint32_t sampleRate = metaData->m_sampleRate; | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |         if (m_sampleRate != sampleRate) | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             qDebug("RemoteSourceWorker::processData: sampleRate: %u", sampleRate); | 
					
						
							|  |  |  |             m_socket.setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, getDataSocketBufferSize(sampleRate)); | 
					
						
							|  |  |  |             m_sampleRate = sampleRate; | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // create the first block for this index
 | 
					
						
							|  |  |  |     if (m_dataFrames[dataBlockIndex] == nullptr) { | 
					
						
							|  |  |  |         m_dataFrames[dataBlockIndex] = new RemoteDataFrame(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_frameIndex < 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // initialize virgin block with the frame index
 | 
					
						
							|  |  |  |         m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_frameIndex = superBlock->m_header.m_frameIndex; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // if the frame index is not the same for the same slot it means we are starting a new frame
 | 
					
						
							|  |  |  |         uint32_t frameIndex = m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_frameIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (superBlock->m_header.m_frameIndex != frameIndex) | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             m_dataQueue->push(m_dataFrames[dataBlockIndex]); | 
					
						
							|  |  |  |             m_dataFrames[dataBlockIndex] = new RemoteDataFrame(); | 
					
						
							|  |  |  |             m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_frameIndex = superBlock->m_header.m_frameIndex; | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     m_dataFrames[dataBlockIndex]->m_superBlocks[superBlock->m_header.m_blockIndex] = *superBlock; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (superBlock->m_header.m_blockIndex == 0) { | 
					
						
							|  |  |  |         m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_metaRetrieved = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (superBlock->m_header.m_blockIndex < RemoteNbOrginalBlocks) { | 
					
						
							|  |  |  |         m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_originalCount++; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_recoveryCount++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_dataFrames[dataBlockIndex]->m_rxControlBlock.m_blockCount++; | 
					
						
							| 
									
										
										
										
											2018-09-01 04:37:23 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-07 04:50:05 +01:00
										 |  |  | int RemoteSourceWorker::getDataSocketBufferSize(uint32_t inSampleRate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-12-18 06:24:47 +01:00
										 |  |  |     // set a floor value at 96 kS/s
 | 
					
						
							|  |  |  |     uint32_t samplerate = inSampleRate < 96000 ? 96000 : inSampleRate; | 
					
						
							| 
									
										
										
										
											2021-12-07 04:50:05 +01:00
										 |  |  |     // 250 ms (1/4s) at current sample rate
 | 
					
						
							|  |  |  |     int bufferSize = (samplerate * 2 * (SDR_RX_SAMP_SZ == 16 ? 2 : 4)) / 4; | 
					
						
							|  |  |  |     qDebug("RemoteSourceWorker::getDataSocketBufferSize: %d bytes", bufferSize); | 
					
						
							|  |  |  |     return bufferSize; | 
					
						
							|  |  |  | } |