| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Copyright (C) 2019 Edouard Griffiths, F4EXB                                   //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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                  //
 | 
					
						
							|  |  |  | // (at your option) any later version.                                           //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // 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/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/crc.hpp>
 | 
					
						
							|  |  |  | #include <boost/cstdint.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | #include "remotesourceworker.h"
 | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | #include "remotesourcesource.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RemoteSourceSource::RemoteSourceSource() : | 
					
						
							|  |  |  |     m_running(false), | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |     m_sourceWorker(nullptr), | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     m_nbCorrectableErrors(0), | 
					
						
							|  |  |  |     m_nbUncorrectableErrors(0), | 
					
						
							|  |  |  |     m_channelSampleRate(48000) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     connect(&m_dataQueue, SIGNAL(dataBlockEnqueued()), this, SLOT(handleData()), Qt::QueuedConnection); | 
					
						
							|  |  |  |     m_cm256p = m_cm256.isInitialized() ? &m_cm256 : 0; | 
					
						
							|  |  |  |     m_currentMeta.init(); | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     m_dataReadQueue.setSize(20); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     applyChannelSettings(m_channelSampleRate, true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RemoteSourceSource::~RemoteSourceSource() | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     stop(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::pull(SampleVector::iterator begin, unsigned int nbSamples) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     std::for_each( | 
					
						
							|  |  |  |         begin, | 
					
						
							|  |  |  |         begin + nbSamples, | 
					
						
							|  |  |  |         [this](Sample& s) { | 
					
						
							|  |  |  |             pullOne(s); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::pullOne(Sample& sample) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-12-19 11:30:48 +01:00
										 |  |  |     m_dataReadQueue.readSample(sample, true); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::start() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qDebug("RemoteSourceSource::start"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_running) { | 
					
						
							|  |  |  |         stop(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |     m_sourceWorker = new RemoteSourceWorker(&m_dataQueue); | 
					
						
							|  |  |  |     m_sourceWorker->moveToThread(&m_sourceWorkerThread); | 
					
						
							|  |  |  |     startWorker(); | 
					
						
							|  |  |  |     m_sourceWorker->dataBind(m_settings.m_dataAddress, m_settings.m_dataPort); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     m_running = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::stop() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qDebug("RemoteSourceSource::stop"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |     if (m_sourceWorker) | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |         stopWorker(); | 
					
						
							|  |  |  |         m_sourceWorker->deleteLater(); | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  |         m_sourceWorker = nullptr; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_running = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  | void RemoteSourceSource::startWorker() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_sourceWorker->startWork(); | 
					
						
							|  |  |  |     m_sourceWorkerThread.start(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::stopWorker() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	m_sourceWorker->stopWork(); | 
					
						
							|  |  |  | 	m_sourceWorkerThread.quit(); | 
					
						
							|  |  |  | 	m_sourceWorkerThread.wait(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | void RemoteSourceSource::handleData() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     RemoteDataFrame* dataFrame; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     while (m_running && ((dataFrame = m_dataQueue.pop()) != nullptr)) { | 
					
						
							|  |  |  |         handleDataFrame(dataFrame); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  | void RemoteSourceSource::handleDataFrame(RemoteDataFrame* dataFrame) | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |     if (dataFrame->m_rxControlBlock.m_blockCount < RemoteNbOrginalBlocks) | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-12-18 06:24:47 +01:00
										 |  |  |         qWarning("RemoteSourceSource::handleDataFrame: incomplete data frame (%d): not processing", dataFrame->m_rxControlBlock.m_blockCount); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int blockCount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (int blockIndex = 0; blockIndex < 256; blockIndex++) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             if ((blockIndex == 0) && (dataFrame->m_rxControlBlock.m_metaRetrieved)) | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             { | 
					
						
							|  |  |  |                 m_cm256DescriptorBlocks[blockCount].Index = 0; | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                 m_cm256DescriptorBlocks[blockCount].Block = (void *) &(dataFrame->m_superBlocks[0].m_protectedBlock); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |                 blockCount++; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             else if (dataFrame->m_superBlocks[blockIndex].m_header.m_blockIndex != 0) | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                 m_cm256DescriptorBlocks[blockCount].Index = dataFrame->m_superBlocks[blockIndex].m_header.m_blockIndex; | 
					
						
							|  |  |  |                 m_cm256DescriptorBlocks[blockCount].Block = (void *) &(dataFrame->m_superBlocks[blockIndex].m_protectedBlock); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |                 blockCount++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |         //qDebug("RemoteSourceSource::handleDataFrame: frame: %u blocks: %d", dataFrame.m_rxControlBlock.m_frameIndex, blockCount);
 | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Need to use the CM256 recovery
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |         if (m_cm256p &&(dataFrame->m_rxControlBlock.m_originalCount < RemoteNbOrginalBlocks)) | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             qDebug("RemoteSourceSource::handleDataFrame: %d recovery blocks", dataFrame->m_rxControlBlock.m_recoveryCount); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             CM256::cm256_encoder_params paramsCM256; | 
					
						
							|  |  |  |             paramsCM256.BlockBytes = sizeof(RemoteProtectedBlock); // never changes
 | 
					
						
							|  |  |  |             paramsCM256.OriginalCount = RemoteNbOrginalBlocks;  // never changes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (m_currentMeta.m_tv_sec == 0) { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                 paramsCM256.RecoveryCount = dataFrame->m_rxControlBlock.m_recoveryCount; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 paramsCM256.RecoveryCount = m_currentMeta.m_nbFECBlocks; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // update counters
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             if (dataFrame->m_rxControlBlock.m_originalCount < RemoteNbOrginalBlocks - paramsCM256.RecoveryCount) { | 
					
						
							|  |  |  |                 m_nbUncorrectableErrors += RemoteNbOrginalBlocks - paramsCM256.RecoveryCount - dataFrame->m_rxControlBlock.m_originalCount; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                 m_nbCorrectableErrors += dataFrame->m_rxControlBlock.m_recoveryCount; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (m_cm256.cm256_decode(paramsCM256, m_cm256DescriptorBlocks)) // CM256 decode
 | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                 qWarning() << "RemoteSourceSource::handleDataFrame: decode CM256 error:" | 
					
						
							|  |  |  |                         << " m_originalCount: " << dataFrame->m_rxControlBlock.m_originalCount | 
					
						
							|  |  |  |                         << " m_recoveryCount: " << dataFrame->m_rxControlBlock.m_recoveryCount; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                 for (int ir = 0; ir < dataFrame->m_rxControlBlock.m_recoveryCount; ir++) // restore missing blocks
 | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |                 { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                     int recoveryIndex = RemoteNbOrginalBlocks - dataFrame->m_rxControlBlock.m_recoveryCount + ir; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |                     int blockIndex = m_cm256DescriptorBlocks[recoveryIndex].Index; | 
					
						
							|  |  |  |                     RemoteProtectedBlock *recoveredBlock = | 
					
						
							|  |  |  |                             (RemoteProtectedBlock *) m_cm256DescriptorBlocks[recoveryIndex].Block; | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                     memcpy((void *) &(dataFrame->m_superBlocks[blockIndex].m_protectedBlock), recoveredBlock, sizeof(RemoteProtectedBlock)); | 
					
						
							|  |  |  |                     if ((blockIndex == 0) && !dataFrame->m_rxControlBlock.m_metaRetrieved) { | 
					
						
							|  |  |  |                         dataFrame->m_rxControlBlock.m_metaRetrieved = true; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Validate block zero and retrieve its data
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |         if (dataFrame->m_rxControlBlock.m_metaRetrieved) | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |             RemoteMetaDataFEC *metaData = (RemoteMetaDataFEC *) &(dataFrame->m_superBlocks[0].m_protectedBlock); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             boost::crc_32_type crc32; | 
					
						
							|  |  |  |             crc32.process_bytes(metaData, sizeof(RemoteMetaDataFEC)-4); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (crc32.checksum() == metaData->m_crc32) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (!(m_currentMeta == *metaData)) | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                     printMeta("RemoteSourceSource::handleDataFrame", metaData); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     if (m_currentMeta.m_sampleRate != metaData->m_sampleRate) { | 
					
						
							|  |  |  |                         emit newRemoteSampleRate(metaData->m_sampleRate); | 
					
						
							|  |  |  |                         // returns via applyChannelSettings to set interpolator
 | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 m_currentMeta = *metaData; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |                 qWarning() << "RemoteSource::handleDataFrame: recovered meta: invalid CRC32"; | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 10:44:58 +01:00
										 |  |  |         m_dataReadQueue.push(dataFrame); // Push into R/W buffer
 | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::printMeta(const QString& header, RemoteMetaDataFEC *metaData) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qDebug().noquote() << header << ": " | 
					
						
							|  |  |  |             << "|" << metaData->m_centerFrequency | 
					
						
							|  |  |  |             << ":" << metaData->m_sampleRate | 
					
						
							|  |  |  |             << ":" << (int) (metaData->m_sampleBytes & 0xF) | 
					
						
							|  |  |  |             << ":" << (int) metaData->m_sampleBits | 
					
						
							|  |  |  |             << ":" << (int) metaData->m_nbOriginalBlocks | 
					
						
							|  |  |  |             << ":" << (int) metaData->m_nbFECBlocks | 
					
						
							| 
									
										
										
										
											2021-12-23 16:27:19 +01:00
										 |  |  |             << "|" << metaData->m_deviceIndex | 
					
						
							|  |  |  |             << ":" << metaData->m_channelIndex | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |             << "|" << metaData->m_tv_sec | 
					
						
							|  |  |  |             << ":" << metaData->m_tv_usec | 
					
						
							|  |  |  |             << "|"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::dataBind(const QString& dataAddress, uint16_t dataPort) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-12 10:03:08 +02:00
										 |  |  |     if (m_sourceWorker) { | 
					
						
							|  |  |  |         m_sourceWorker->dataBind(dataAddress, dataPort); | 
					
						
							| 
									
										
										
										
											2019-11-15 01:04:24 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_settings.m_dataAddress = dataAddress; | 
					
						
							|  |  |  |     m_settings.m_dataPort = dataPort; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteSourceSource::applyChannelSettings(int channelSampleRate, bool force) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qDebug() << "RemoteSourceSource::applyChannelSettings:" | 
					
						
							|  |  |  |             << " channelSampleRate: " << channelSampleRate | 
					
						
							|  |  |  |             << " force: " << force; | 
					
						
							|  |  |  |     m_channelSampleRate = channelSampleRate; | 
					
						
							| 
									
										
										
										
											2021-12-07 05:58:17 +01:00
										 |  |  | } |