SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
hackrfoutputthread.cpp
Go to the documentation of this file.
1 // Copyright (C) 2017 Edouard Griffiths, F4EXB //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #include "hackrfoutputthread.h"
19 
20 #include <stdio.h>
21 #include <errno.h>
22 
23 #include "dsp/samplesourcefifo.h"
24 
25 HackRFOutputThread::HackRFOutputThread(hackrf_device* dev, SampleSourceFifo* sampleFifo, QObject* parent) :
26  QThread(parent),
27  m_running(false),
28  m_dev(dev),
29  m_sampleFifo(sampleFifo),
30  m_log2Interp(0),
31  m_fcPos(2)
32 {
33  std::fill(m_buf, m_buf + 2*HACKRF_BLOCKSIZE, 0);
34 }
35 
37 {
38  stopWork();
39 }
40 
42 {
43  m_startWaitMutex.lock();
44  start();
45  while(!m_running)
46  m_startWaiter.wait(&m_startWaitMutex, 100);
47  m_startWaitMutex.unlock();
48 }
49 
51 {
52  if (!m_running) return;
53  qDebug("HackRFOutputThread::stopWork");
54  m_running = false;
55  wait();
56 }
57 
58 void HackRFOutputThread::setLog2Interpolation(unsigned int log2Interp)
59 {
60  m_log2Interp = log2Interp;
61 }
62 
64 {
65  m_fcPos = fcPos;
66 }
67 
69 {
70  hackrf_error rc;
71 
72  m_running = true;
73  m_startWaiter.wakeAll();
74 
75 
76  if (hackrf_is_streaming(m_dev) == HACKRF_TRUE)
77  {
78  qDebug("HackRFInputThread::run: HackRF is streaming already");
79  }
80  else
81  {
82  qDebug("HackRFInputThread::run: HackRF is not streaming");
83 
84  rc = (hackrf_error) hackrf_start_tx(m_dev, tx_callback, this);
85 
86  if (rc == HACKRF_SUCCESS)
87  {
88  qDebug("HackRFOutputThread::run: started HackRF Tx");
89  }
90  else
91  {
92  qDebug("HackRFOutputThread::run: failed to start HackRF Tx: %s", hackrf_error_name(rc));
93  }
94  }
95 
96  while ((m_running) && (hackrf_is_streaming(m_dev) == HACKRF_TRUE))
97  {
98  usleep(200000);
99  }
100 
101  if (hackrf_is_streaming(m_dev) == HACKRF_TRUE)
102  {
103  rc = (hackrf_error) hackrf_stop_tx(m_dev);
104 
105  if (rc == HACKRF_SUCCESS)
106  {
107  qDebug("HackRFOutputThread::run: stopped HackRF Tx");
108  }
109  else
110  {
111  qDebug("HackRFOutputThread::run: failed to stop HackRF Tx: %s", hackrf_error_name(rc));
112  }
113  }
114 
115  m_running = false;
116 }
117 
118 // Interpolate according to specified log2 (ex: log2=4 => interp=16)
119 void HackRFOutputThread::callback(qint8* buf, qint32 len)
120 {
121  SampleVector::iterator beginRead;
122  m_sampleFifo->readAdvance(beginRead, len/(2*(1<<m_log2Interp)));
123  beginRead -= len/2;
124 
125  if (m_log2Interp == 0)
126  {
127  m_interpolators.interpolate1(&beginRead, buf, len);
128  }
129  else
130  {
131  if (m_fcPos == 0) // Infra
132  {
133  switch (m_log2Interp)
134  {
135  case 1:
136  m_interpolators.interpolate2_inf(&beginRead, buf, len);
137  break;
138  case 2:
139  m_interpolators.interpolate4_inf(&beginRead, buf, len);
140  break;
141  case 3:
142  m_interpolators.interpolate8_inf(&beginRead, buf, len);
143  break;
144  case 4:
145  m_interpolators.interpolate16_inf(&beginRead, buf, len);
146  break;
147  case 5:
148  m_interpolators.interpolate32_inf(&beginRead, buf, len);
149  break;
150  case 6:
151  m_interpolators.interpolate64_inf(&beginRead, buf, len);
152  break;
153  default:
154  break;
155  }
156  }
157  else if (m_fcPos == 1) // Supra
158  {
159  switch (m_log2Interp)
160  {
161  case 1:
162  m_interpolators.interpolate2_sup(&beginRead, buf, len);
163  break;
164  case 2:
165  m_interpolators.interpolate4_sup(&beginRead, buf, len);
166  break;
167  case 3:
168  m_interpolators.interpolate8_sup(&beginRead, buf, len);
169  break;
170  case 4:
171  m_interpolators.interpolate16_sup(&beginRead, buf, len);
172  break;
173  case 5:
174  m_interpolators.interpolate32_sup(&beginRead, buf, len);
175  break;
176  case 6:
177  m_interpolators.interpolate64_sup(&beginRead, buf, len);
178  break;
179  default:
180  break;
181  }
182  }
183  else if (m_fcPos == 2) // Center
184  {
185  switch (m_log2Interp)
186  {
187  case 1:
188  m_interpolators.interpolate2_cen(&beginRead, buf, len);
189  break;
190  case 2:
191  m_interpolators.interpolate4_cen(&beginRead, buf, len);
192  break;
193  case 3:
194  m_interpolators.interpolate8_cen(&beginRead, buf, len);
195  break;
196  case 4:
197  m_interpolators.interpolate16_cen(&beginRead, buf, len);
198  break;
199  case 5:
200  m_interpolators.interpolate32_cen(&beginRead, buf, len);
201  break;
202  case 6:
203  m_interpolators.interpolate64_cen(&beginRead, buf, len);
204  break;
205  default:
206  break;
207  }
208  }
209  }
210 }
211 
212 int HackRFOutputThread::tx_callback(hackrf_transfer* transfer)
213 {
214  HackRFOutputThread *thread = (HackRFOutputThread *) transfer->tx_ctx;
215  qint32 bytes_to_write = transfer->valid_length;
216  thread->callback((qint8 *) transfer->buffer, bytes_to_write);
217  return 0;
218 }
Interpolators< qint8, SDR_TX_SAMP_SZ, 8 > m_interpolators
void interpolate64_sup(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate64_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
unsigned int m_log2Interp
void interpolate8_inf(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate32_inf(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate32_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate4_inf(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
hackrf_device * m_dev
void interpolate8_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate2_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void readAdvance(SampleVector::iterator &readUntil, unsigned int nbSamples)
QWaitCondition m_startWaiter
void setLog2Interpolation(unsigned int log2_interp)
SampleSourceFifo * m_sampleFifo
HackRFOutputThread(hackrf_device *dev, SampleSourceFifo *sampleFifo, QObject *parent=NULL)
static int tx_callback(hackrf_transfer *transfer)
#define HACKRF_BLOCKSIZE
void interpolate16_inf(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate2_sup(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate2_inf(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate1(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate16_sup(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate32_sup(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void callback(qint8 *buf, qint32 len)
void interpolate8_sup(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate16_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate4_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void interpolate64_inf(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
qint8 m_buf[2 *HACKRF_BLOCKSIZE]
void interpolate4_sup(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void setFcPos(int fcPos)