| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Copyright (C) 2017 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                  //
 | 
					
						
							| 
									
										
										
										
											2019-04-11 06:39:30 +02:00
										 |  |  | // (at your option) any later version.                                           //
 | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01: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/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hackrfoutputthread.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "dsp/samplesourcefifo.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HackRFOutputThread::HackRFOutputThread(hackrf_device* dev, SampleSourceFifo* sampleFifo, QObject* parent) : | 
					
						
							|  |  |  | 	QThread(parent), | 
					
						
							|  |  |  | 	m_running(false), | 
					
						
							|  |  |  | 	m_dev(dev), | 
					
						
							|  |  |  | 	m_sampleFifo(sampleFifo), | 
					
						
							| 
									
										
										
										
											2019-06-14 16:58:09 +02:00
										 |  |  | 	m_log2Interp(0), | 
					
						
							|  |  |  |     m_fcPos(2) | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-24 10:29:27 +01:00
										 |  |  |     std::fill(m_buf, m_buf + 2*HACKRF_BLOCKSIZE, 0); | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HackRFOutputThread::~HackRFOutputThread() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	stopWork(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HackRFOutputThread::startWork() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-01-10 01:02:28 +01:00
										 |  |  | 	m_startWaitMutex.lock(); | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 	start(); | 
					
						
							|  |  |  | 	while(!m_running) | 
					
						
							|  |  |  | 		m_startWaiter.wait(&m_startWaitMutex, 100); | 
					
						
							| 
									
										
										
										
											2017-01-10 01:02:28 +01:00
										 |  |  | 	m_startWaitMutex.unlock(); | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HackRFOutputThread::stopWork() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-08-08 21:30:04 +02:00
										 |  |  |     if (!m_running) return; | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 	qDebug("HackRFOutputThread::stopWork"); | 
					
						
							|  |  |  | 	m_running = false; | 
					
						
							|  |  |  | 	wait(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HackRFOutputThread::setLog2Interpolation(unsigned int log2Interp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	m_log2Interp = log2Interp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:50 +02:00
										 |  |  | void HackRFOutputThread::setFcPos(int fcPos) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	m_fcPos = fcPos; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | void HackRFOutputThread::run() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	hackrf_error rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |     m_running = true; | 
					
						
							|  |  |  |     m_startWaiter.wakeAll(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |     if (hackrf_is_streaming(m_dev) == HACKRF_TRUE) | 
					
						
							| 
									
										
										
										
											2017-04-14 01:41:02 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |         qDebug("HackRFInputThread::run: HackRF is streaming already"); | 
					
						
							| 
									
										
										
										
											2017-04-14 01:41:02 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |         qDebug("HackRFInputThread::run: HackRF is not streaming"); | 
					
						
							| 
									
										
										
										
											2017-04-14 01:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |         rc = (hackrf_error) hackrf_start_tx(m_dev, tx_callback, this); | 
					
						
							| 
									
										
										
										
											2017-01-11 01:21:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |         if (rc == HACKRF_SUCCESS) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug("HackRFOutputThread::run: started HackRF Tx"); | 
					
						
							| 
									
										
										
										
											2017-04-14 01:41:02 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug("HackRFOutputThread::run: failed to start HackRF Tx: %s", hackrf_error_name(rc)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-14 01:41:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |     while ((m_running) && (hackrf_is_streaming(m_dev) == HACKRF_TRUE)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         usleep(200000); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |     if (hackrf_is_streaming(m_dev) == HACKRF_TRUE) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         rc = (hackrf_error) hackrf_stop_tx(m_dev); | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 16:35:05 +02:00
										 |  |  |         if (rc == HACKRF_SUCCESS) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug("HackRFOutputThread::run: stopped HackRF Tx"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug("HackRFOutputThread::run: failed to stop HackRF Tx: %s", hackrf_error_name(rc)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-10 01:02:28 +01:00
										 |  |  | 	m_running = false; | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //  Interpolate according to specified log2 (ex: log2=4 => interp=16)
 | 
					
						
							| 
									
										
										
										
											2017-01-08 13:04:06 +01:00
										 |  |  | void HackRFOutputThread::callback(qint8* buf, qint32 len) | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     SampleVector::iterator beginRead; | 
					
						
							| 
									
										
										
										
											2017-01-08 13:04:06 +01:00
										 |  |  |     m_sampleFifo->readAdvance(beginRead, len/(2*(1<<m_log2Interp))); | 
					
						
							|  |  |  |     beginRead -= len/2; | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (m_log2Interp == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2017-01-08 13:04:06 +01:00
										 |  |  | 	    m_interpolators.interpolate1(&beginRead, buf, len); | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:50 +02:00
										 |  |  | 		if (m_fcPos == 0) // Infra
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  |             switch (m_log2Interp) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 1: | 
					
						
							|  |  |  |                 m_interpolators.interpolate2_inf(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							|  |  |  |                 m_interpolators.interpolate4_inf(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2019-04-01 02:12:50 +02:00
										 |  |  |             case 3: | 
					
						
							|  |  |  |                 m_interpolators.interpolate8_inf(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 4: | 
					
						
							|  |  |  |                 m_interpolators.interpolate16_inf(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 5: | 
					
						
							|  |  |  |                 m_interpolators.interpolate32_inf(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2019-04-01 03:24:45 +02:00
										 |  |  |             case 6: | 
					
						
							|  |  |  |                 m_interpolators.interpolate64_inf(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:50 +02:00
										 |  |  |             default: | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (m_fcPos == 1) // Supra
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             switch (m_log2Interp) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 1: | 
					
						
							|  |  |  |                 m_interpolators.interpolate2_sup(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							|  |  |  |                 m_interpolators.interpolate4_sup(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2019-04-01 02:12:50 +02:00
										 |  |  |             case 3: | 
					
						
							|  |  |  |                 m_interpolators.interpolate8_sup(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 4: | 
					
						
							|  |  |  |                 m_interpolators.interpolate16_sup(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 5: | 
					
						
							|  |  |  |                 m_interpolators.interpolate32_sup(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2019-04-01 03:24:45 +02:00
										 |  |  |             case 6: | 
					
						
							|  |  |  |                 m_interpolators.interpolate64_sup(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:50 +02:00
										 |  |  |             default: | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (m_fcPos == 2) // Center
 | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:50 +02:00
										 |  |  |             switch (m_log2Interp) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 1: | 
					
						
							|  |  |  |                 m_interpolators.interpolate2_cen(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							|  |  |  |                 m_interpolators.interpolate4_cen(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 3: | 
					
						
							|  |  |  |                 m_interpolators.interpolate8_cen(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 4: | 
					
						
							|  |  |  |                 m_interpolators.interpolate16_cen(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 5: | 
					
						
							|  |  |  |                 m_interpolators.interpolate32_cen(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 6: | 
					
						
							|  |  |  |                 m_interpolators.interpolate64_cen(&beginRead, buf, len); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int HackRFOutputThread::tx_callback(hackrf_transfer* transfer) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-01-08 10:27:57 +01:00
										 |  |  |     HackRFOutputThread *thread = (HackRFOutputThread *) transfer->tx_ctx; | 
					
						
							| 
									
										
										
										
											2017-01-08 13:04:06 +01:00
										 |  |  |     qint32 bytes_to_write = transfer->valid_length; | 
					
						
							|  |  |  | 	thread->callback((qint8 *) transfer->buffer, bytes_to_write); | 
					
						
							| 
									
										
										
										
											2017-01-08 04:13:20 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } |