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.
Classes | Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
SoapySDROutputThread Class Reference

#include <soapysdroutputthread.h>

Inherits QThread.

+ Collaboration diagram for SoapySDROutputThread:

Classes

struct  Channel
 

Public Member Functions

 SoapySDROutputThread (SoapySDR::Device *dev, unsigned int nbTxChannels, QObject *parent=0)
 
 ~SoapySDROutputThread ()
 
void startWork ()
 
void stopWork ()
 
bool isRunning () const
 
unsigned int getNbChannels () const
 
void setLog2Interpolation (unsigned int channel, unsigned int log2_interp)
 
unsigned int getLog2Interpolation (unsigned int channel) const
 
void setSampleRate (unsigned int sampleRate)
 
unsigned int getSampleRate () const
 
void setFifo (unsigned int channel, SampleSourceFifo *sampleFifo)
 
SampleSourceFifogetFifo (unsigned int channel)
 

Private Types

enum  InterpolatorType { Interpolator8, Interpolator12, Interpolator16, InterpolatorFloat }
 

Private Member Functions

void run ()
 
unsigned int getNbFifos ()
 
void callbackSO8 (qint8 *buf, qint32 len, unsigned int channel=0)
 
void callbackSO12 (qint16 *buf, qint32 len, unsigned int channel=0)
 
void callbackSO16 (qint16 *buf, qint32 len, unsigned int channel=0)
 
void callbackSOIF (float *buf, qint32 len, unsigned int channel=0)
 
void callbackMO (std::vector< void *> &buffs, qint32 samplesPerChannel)
 

Private Attributes

QMutex m_startWaitMutex
 
QWaitCondition m_startWaiter
 
bool m_running
 
SoapySDR::Device * m_dev
 
Channelm_channels
 Array of channels dynamically allocated for the given number of Tx channels. More...
 
unsigned int m_sampleRate
 
unsigned int m_nbChannels
 
InterpolatorType m_interpolatorType
 

Detailed Description

Definition at line 34 of file soapysdroutputthread.h.

Member Enumeration Documentation

◆ InterpolatorType

Constructor & Destructor Documentation

◆ SoapySDROutputThread()

SoapySDROutputThread::SoapySDROutputThread ( SoapySDR::Device *  dev,
unsigned int  nbTxChannels,
QObject *  parent = 0 
)

Definition at line 27 of file soapysdroutputthread.cpp.

References m_channels.

27  :
28  QThread(parent),
29  m_running(false),
30  m_dev(dev),
31  m_sampleRate(0),
32  m_nbChannels(nbTxChannels),
34 {
35  qDebug("SoapySDROutputThread::SoapySDROutputThread");
36  m_channels = new Channel[nbTxChannels];
37 }
SoapySDR::Device * m_dev
InterpolatorType m_interpolatorType
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.

◆ ~SoapySDROutputThread()

SoapySDROutputThread::~SoapySDROutputThread ( )

Definition at line 39 of file soapysdroutputthread.cpp.

References m_channels, m_running, and stopWork().

40 {
41  qDebug("SoapySDROutputThread::~SoapySDROutputThread");
42 
43  if (m_running) {
44  stopWork();
45  }
46 
47  delete[] m_channels;
48 }
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the call graph for this function:

Member Function Documentation

◆ callbackMO()

void SoapySDROutputThread::callbackMO ( std::vector< void *> &  buffs,
qint32  samplesPerChannel 
)
private

Definition at line 237 of file soapysdroutputthread.cpp.

References callbackSO12(), callbackSO16(), callbackSO8(), Interpolator12, Interpolator16, Interpolator8, InterpolatorFloat, m_channels, m_interpolatorType, and m_nbChannels.

Referenced by run().

238 {
239  for(unsigned int ichan = 0; ichan < m_nbChannels; ichan++)
240  {
241  if (m_channels[ichan].m_sampleFifo)
242  {
243  switch (m_interpolatorType)
244  {
245  case Interpolator8:
246  callbackSO8((qint8*) buffs[ichan], samplesPerChannel, ichan);
247  break;
248  case Interpolator12:
249  callbackSO12((qint16*) buffs[ichan], samplesPerChannel, ichan);
250  break;
251  case Interpolator16:
252  callbackSO16((qint16*) buffs[ichan], samplesPerChannel, ichan);
253  break;
254  case InterpolatorFloat:
255  default:
256  // TODO
257  break;
258  }
259  }
260  else // no FIFO for this channel means channel is unused: fill with zeros
261  {
262  switch (m_interpolatorType)
263  {
264  case Interpolator8:
265  std::fill((qint8*) buffs[ichan], (qint8*) buffs[ichan] + 2*samplesPerChannel, 0);
266  break;
267  case Interpolator12:
268  case Interpolator16:
269  std::fill((qint16*) buffs[ichan], (qint16*) buffs[ichan] + 2*samplesPerChannel, 0);
270  break;
271  case InterpolatorFloat:
272  default:
273  std::fill((float*) buffs[ichan], (float*) buffs[ichan] + 2*samplesPerChannel, 0.0f);
274  break;
275  }
276  }
277  }
278 }
void callbackSO16(qint16 *buf, qint32 len, unsigned int channel=0)
InterpolatorType m_interpolatorType
void callbackSO8(qint8 *buf, qint32 len, unsigned int channel=0)
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
void callbackSO12(qint16 *buf, qint32 len, unsigned int channel=0)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ callbackSO12()

void SoapySDROutputThread::callbackSO12 ( qint16 *  buf,
qint32  len,
unsigned int  channel = 0 
)
private

Definition at line 335 of file soapysdroutputthread.cpp.

References SampleSourceFifo::getRWBalance(), Interpolators< T, SdrBits, OutputBits >::interpolate1(), Interpolators< T, SdrBits, OutputBits >::interpolate16_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate2_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate32_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate4_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate64_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate8_cen(), m_channels, SoapySDROutputThread::Channel::m_interpolators12, SoapySDROutputThread::Channel::m_sampleFifo, and SampleSourceFifo::readAdvance().

Referenced by callbackMO(), and run().

336 {
337  if (m_channels[channel].m_sampleFifo)
338  {
339  float bal = m_channels[channel].m_sampleFifo->getRWBalance();
340 
341  if (bal < -0.25) {
342  qDebug("SoapySDROutputThread::callbackSO12: read lags: %f", bal);
343  } else if (bal > 0.25) {
344  qDebug("SoapySDROutputThread::callbackSO12: read leads: %f", bal);
345  }
346 
347  SampleVector::iterator beginRead;
348  m_channels[channel].m_sampleFifo->readAdvance(beginRead, len/(1<<m_channels[channel].m_log2Interp));
349  beginRead -= len;
350 
351  if (m_channels[channel].m_log2Interp == 0)
352  {
353  m_channels[channel].m_interpolators12.interpolate1(&beginRead, buf, len*2);
354  }
355  else
356  {
357  switch (m_channels[channel].m_log2Interp)
358  {
359  case 1:
360  m_channels[channel].m_interpolators12.interpolate2_cen(&beginRead, buf, len*2);
361  break;
362  case 2:
363  m_channels[channel].m_interpolators12.interpolate4_cen(&beginRead, buf, len*2);
364  break;
365  case 3:
366  m_channels[channel].m_interpolators12.interpolate8_cen(&beginRead, buf, len*2);
367  break;
368  case 4:
369  m_channels[channel].m_interpolators12.interpolate16_cen(&beginRead, buf, len*2);
370  break;
371  case 5:
372  m_channels[channel].m_interpolators12.interpolate32_cen(&beginRead, buf, len*2);
373  break;
374  case 6:
375  m_channels[channel].m_interpolators12.interpolate64_cen(&beginRead, buf, len*2);
376  break;
377  default:
378  break;
379  }
380  }
381  }
382  else
383  {
384  std::fill(buf, buf+2*len, 0);
385  }
386 }
void interpolate64_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
float getRWBalance() const
Interpolators< qint16, SDR_TX_SAMP_SZ, 12 > m_interpolators12
void interpolate32_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
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)
void interpolate1(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)
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ callbackSO16()

void SoapySDROutputThread::callbackSO16 ( qint16 *  buf,
qint32  len,
unsigned int  channel = 0 
)
private

Definition at line 388 of file soapysdroutputthread.cpp.

References SampleSourceFifo::getRWBalance(), Interpolators< T, SdrBits, OutputBits >::interpolate1(), Interpolators< T, SdrBits, OutputBits >::interpolate16_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate2_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate32_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate4_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate64_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate8_cen(), m_channels, SoapySDROutputThread::Channel::m_interpolators16, SoapySDROutputThread::Channel::m_sampleFifo, and SampleSourceFifo::readAdvance().

Referenced by callbackMO(), and run().

389 {
390  if (m_channels[channel].m_sampleFifo)
391  {
392  float bal = m_channels[channel].m_sampleFifo->getRWBalance();
393 
394  if (bal < -0.25) {
395  qDebug("SoapySDROutputThread::callbackSO16: read lags: %f", bal);
396  } else if (bal > 0.25) {
397  qDebug("SoapySDROutputThread::callbackSO16: read leads: %f", bal);
398  }
399 
400  SampleVector::iterator beginRead;
401  m_channels[channel].m_sampleFifo->readAdvance(beginRead, len/(1<<m_channels[channel].m_log2Interp));
402  beginRead -= len;
403 
404  if (m_channels[channel].m_log2Interp == 0)
405  {
406  m_channels[channel].m_interpolators16.interpolate1(&beginRead, buf, len*2);
407  }
408  else
409  {
410  switch (m_channels[channel].m_log2Interp)
411  {
412  case 1:
413  m_channels[channel].m_interpolators16.interpolate2_cen(&beginRead, buf, len*2);
414  break;
415  case 2:
416  m_channels[channel].m_interpolators16.interpolate4_cen(&beginRead, buf, len*2);
417  break;
418  case 3:
419  m_channels[channel].m_interpolators16.interpolate8_cen(&beginRead, buf, len*2);
420  break;
421  case 4:
422  m_channels[channel].m_interpolators16.interpolate16_cen(&beginRead, buf, len*2);
423  break;
424  case 5:
425  m_channels[channel].m_interpolators16.interpolate32_cen(&beginRead, buf, len*2);
426  break;
427  case 6:
428  m_channels[channel].m_interpolators16.interpolate64_cen(&beginRead, buf, len*2);
429  break;
430  default:
431  break;
432  }
433  }
434  }
435  else
436  {
437  std::fill(buf, buf+2*len, 0);
438  }
439 }
void interpolate64_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
float getRWBalance() const
void interpolate32_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
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)
Interpolators< qint16, SDR_TX_SAMP_SZ, 16 > m_interpolators16
void interpolate1(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)
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ callbackSO8()

void SoapySDROutputThread::callbackSO8 ( qint8 *  buf,
qint32  len,
unsigned int  channel = 0 
)
private

Definition at line 282 of file soapysdroutputthread.cpp.

References SampleSourceFifo::getRWBalance(), Interpolators< T, SdrBits, OutputBits >::interpolate1(), Interpolators< T, SdrBits, OutputBits >::interpolate16_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate2_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate32_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate4_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate64_cen(), Interpolators< T, SdrBits, OutputBits >::interpolate8_cen(), m_channels, SoapySDROutputThread::Channel::m_interpolators8, SoapySDROutputThread::Channel::m_sampleFifo, and SampleSourceFifo::readAdvance().

Referenced by callbackMO(), and run().

283 {
284  if (m_channels[channel].m_sampleFifo)
285  {
286  float bal = m_channels[channel].m_sampleFifo->getRWBalance();
287 
288  if (bal < -0.25) {
289  qDebug("SoapySDROutputThread::callbackSO8: read lags: %f", bal);
290  } else if (bal > 0.25) {
291  qDebug("SoapySDROutputThread::callbackSO8: read leads: %f", bal);
292  }
293 
294  SampleVector::iterator beginRead;
295  m_channels[channel].m_sampleFifo->readAdvance(beginRead, len/(1<<m_channels[channel].m_log2Interp));
296  beginRead -= len;
297 
298  if (m_channels[channel].m_log2Interp == 0)
299  {
300  m_channels[channel].m_interpolators8.interpolate1(&beginRead, buf, len*2);
301  }
302  else
303  {
304  switch (m_channels[channel].m_log2Interp)
305  {
306  case 1:
307  m_channels[channel].m_interpolators8.interpolate2_cen(&beginRead, buf, len*2);
308  break;
309  case 2:
310  m_channels[channel].m_interpolators8.interpolate4_cen(&beginRead, buf, len*2);
311  break;
312  case 3:
313  m_channels[channel].m_interpolators8.interpolate8_cen(&beginRead, buf, len*2);
314  break;
315  case 4:
316  m_channels[channel].m_interpolators8.interpolate16_cen(&beginRead, buf, len*2);
317  break;
318  case 5:
319  m_channels[channel].m_interpolators8.interpolate32_cen(&beginRead, buf, len*2);
320  break;
321  case 6:
322  m_channels[channel].m_interpolators8.interpolate64_cen(&beginRead, buf, len*2);
323  break;
324  default:
325  break;
326  }
327  }
328  }
329  else
330  {
331  std::fill(buf, buf+2*len, 0);
332  }
333 }
void interpolate64_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
float getRWBalance() const
void interpolate32_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
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)
Interpolators< qint8, SDR_TX_SAMP_SZ, 8 > m_interpolators8
void readAdvance(SampleVector::iterator &readUntil, unsigned int nbSamples)
void interpolate1(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)
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ callbackSOIF()

void SoapySDROutputThread::callbackSOIF ( float *  buf,
qint32  len,
unsigned int  channel = 0 
)
private

Definition at line 442 of file soapysdroutputthread.cpp.

References SampleSourceFifo::getRWBalance(), InterpolatorsIF< OutBits, InBits >::interpolate1(), InterpolatorsIF< OutBits, InBits >::interpolate16_cen(), InterpolatorsIF< OutBits, InBits >::interpolate2_cen(), InterpolatorsIF< OutBits, InBits >::interpolate32_cen(), InterpolatorsIF< OutBits, InBits >::interpolate4_cen(), InterpolatorsIF< OutBits, InBits >::interpolate64_cen(), InterpolatorsIF< OutBits, InBits >::interpolate8_cen(), m_channels, SoapySDROutputThread::Channel::m_interpolatorsIF, SoapySDROutputThread::Channel::m_sampleFifo, and SampleSourceFifo::readAdvance().

Referenced by run().

443 {
444  if (m_channels[channel].m_sampleFifo)
445  {
446  float bal = m_channels[channel].m_sampleFifo->getRWBalance();
447 
448  if (bal < -0.25) {
449  qDebug("SoapySDROutputThread::callbackSO16: read lags: %f", bal);
450  } else if (bal > 0.25) {
451  qDebug("SoapySDROutputThread::callbackSO16: read leads: %f", bal);
452  }
453 
454  SampleVector::iterator beginRead;
455  m_channels[channel].m_sampleFifo->readAdvance(beginRead, len/(1<<m_channels[channel].m_log2Interp));
456  beginRead -= len;
457 
458  if (m_channels[channel].m_log2Interp == 0)
459  {
460  m_channels[channel].m_interpolatorsIF.interpolate1(&beginRead, buf, len*2);
461  }
462  else
463  {
464  switch (m_channels[channel].m_log2Interp)
465  {
466  case 1:
467  m_channels[channel].m_interpolatorsIF.interpolate2_cen(&beginRead, buf, len*2);
468  break;
469  case 2:
470  m_channels[channel].m_interpolatorsIF.interpolate4_cen(&beginRead, buf, len*2);
471  break;
472  case 3:
473  m_channels[channel].m_interpolatorsIF.interpolate8_cen(&beginRead, buf, len*2);
474  break;
475  case 4:
476  m_channels[channel].m_interpolatorsIF.interpolate16_cen(&beginRead, buf, len*2);
477  break;
478  case 5:
479  m_channels[channel].m_interpolatorsIF.interpolate32_cen(&beginRead, buf, len*2);
480  break;
481  case 6:
482  m_channels[channel].m_interpolatorsIF.interpolate64_cen(&beginRead, buf, len*2);
483  break;
484  default:
485  break;
486  }
487  }
488  }
489  else
490  {
491  std::fill(buf, buf+2*len, 0.0f);
492  }
493 }
void interpolate16_cen(SampleVector::iterator *it, float *buf, qint32 len, bool invertIQ=false)
void interpolate8_cen(SampleVector::iterator *it, float *buf, qint32 len, bool invertIQ=false)
float getRWBalance() const
void interpolate4_cen(SampleVector::iterator *it, float *buf, qint32 len, bool invertIQ=false)
void interpolate64_cen(SampleVector::iterator *it, float *buf, qint32 len, bool invertIQ=false)
InterpolatorsIF< SDR_TX_SAMP_SZ, SDR_TX_SAMP_SZ > m_interpolatorsIF
void readAdvance(SampleVector::iterator &readUntil, unsigned int nbSamples)
void interpolate2_cen(SampleVector::iterator *it, float *buf, qint32 len, bool invertIQ=false)
void interpolate32_cen(SampleVector::iterator *it, float *buf, qint32 len, bool invertIQ=false)
void interpolate1(SampleVector::iterator *it, float *buf, qint32 len, bool invertIQ=false)
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getFifo()

SampleSourceFifo * SoapySDROutputThread::getFifo ( unsigned int  channel)

Definition at line 228 of file soapysdroutputthread.cpp.

References m_channels, m_nbChannels, and SoapySDROutputThread::Channel::m_sampleFifo.

Referenced by SoapySDROutput::applySettings(), getSampleRate(), SoapySDROutput::start(), and SoapySDROutput::stop().

229 {
230  if (channel < m_nbChannels) {
231  return m_channels[channel].m_sampleFifo;
232  } else {
233  return 0;
234  }
235 }
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the caller graph for this function:

◆ getLog2Interpolation()

unsigned int SoapySDROutputThread::getLog2Interpolation ( unsigned int  channel) const

Definition at line 212 of file soapysdroutputthread.cpp.

References m_channels, SoapySDROutputThread::Channel::m_log2Interp, and m_nbChannels.

Referenced by getNbChannels(), SoapySDROutput::start(), and SoapySDROutput::stop().

213 {
214  if (channel < m_nbChannels) {
215  return m_channels[channel].m_log2Interp;
216  } else {
217  return 0;
218  }
219 }
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the caller graph for this function:

◆ getNbChannels()

unsigned int SoapySDROutputThread::getNbChannels ( ) const
inline

Definition at line 44 of file soapysdroutputthread.h.

References getLog2Interpolation(), m_nbChannels, and setLog2Interpolation().

Referenced by SoapySDROutput::start(), and SoapySDROutput::stop().

44 { return m_nbChannels; }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getNbFifos()

unsigned int SoapySDROutputThread::getNbFifos ( )
private

Definition at line 191 of file soapysdroutputthread.cpp.

References i, m_channels, and m_nbChannels.

Referenced by run().

192 {
193  unsigned int fifoCount = 0;
194 
195  for (unsigned int i = 0; i < m_nbChannels; i++)
196  {
197  if (m_channels[i].m_sampleFifo) {
198  fifoCount++;
199  }
200  }
201 
202  return fifoCount;
203 }
int32_t i
Definition: decimators.h:244
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the caller graph for this function:

◆ getSampleRate()

unsigned int SoapySDROutputThread::getSampleRate ( ) const
inline

Definition at line 48 of file soapysdroutputthread.h.

References getFifo(), m_sampleRate, and setFifo().

48 { return m_sampleRate; }
+ Here is the call graph for this function:

◆ isRunning()

bool SoapySDROutputThread::isRunning ( ) const
inline

Definition at line 43 of file soapysdroutputthread.h.

References m_running.

Referenced by SoapySDROutput::applySettings().

43 { return m_running; }
+ Here is the caller graph for this function:

◆ run()

void SoapySDROutputThread::run ( )
private

Definition at line 76 of file soapysdroutputthread.cpp.

References callbackMO(), callbackSO12(), callbackSO16(), callbackSO8(), callbackSOIF(), getNbFifos(), i, Interpolator12, Interpolator16, Interpolator8, InterpolatorFloat, m_dev, m_interpolatorType, m_nbChannels, m_running, m_sampleRate, and m_startWaiter.

77 {
78  m_running = true;
79  m_startWaiter.wakeAll();
80 
81  unsigned int nbFifos = getNbFifos();
82 
83  if ((m_nbChannels > 0) && (nbFifos > 0))
84  {
85  // build channels list
86  std::vector<std::size_t> channels(m_nbChannels);
87  std::iota(channels.begin(), channels.end(), 0); // Fill with 0, 1, ..., m_nbChannels-1.
88 
89  //initialize the sample rate for all channels
90  qDebug("SoapySDROutputThread::run: m_sampleRate: %u", m_sampleRate);
91  for (const auto &it : channels) {
92  m_dev->setSampleRate(SOAPY_SDR_TX, it, m_sampleRate);
93  }
94 
95  // Determine sample format to be used
96  double fullScale(0.0);
97  std::string format = m_dev->getNativeStreamFormat(SOAPY_SDR_TX, channels.front(), fullScale);
98 
99  qDebug("SoapySDROutputThread::run: format: %s fullScale: %f", format.c_str(), fullScale);
100 
101  if ((format == "CS8") && (fullScale == 128.0)) { // 8 bit signed - native
103  } else if ((format == "CS16") && (fullScale == 2048.0)) { // 12 bit signed - native
105  } else if ((format == "CS16") && (fullScale == 32768.0)) { // 16 bit signed - native
107  } else { // for other types make a conversion to float
109  format = "CF32";
110  }
111 
112  unsigned int elemSize = SoapySDR::formatToSize(format); // sample (I+Q) size in bytes
113  SoapySDR::Stream *stream = m_dev->setupStream(SOAPY_SDR_TX, format, channels);
114 
115  //allocate buffers for the stream read/write
116  const unsigned int numElems = m_dev->getStreamMTU(stream); // number of samples (I+Q)
117  std::vector<std::vector<char>> buffMem(m_nbChannels, std::vector<char>(elemSize*numElems));
118  std::vector<void *> buffs(m_nbChannels);
119 
120  for (std::size_t i = 0; i < m_nbChannels; i++) {
121  buffs[i] = buffMem[i].data();
122  }
123 
124  m_dev->activateStream(stream);
125  int flags(0);
126  long long timeNs(0);
127  float blockTime = ((float) numElems) / (m_sampleRate <= 0 ? 1024000 : m_sampleRate);
128  long initialTtimeoutUs = 10000000 * blockTime; // 10 times the block time
129  long timeoutUs = initialTtimeoutUs < 250000 ? 250000 : initialTtimeoutUs; // 250ms minimum
130 
131  qDebug("SoapySDROutputThread::run: numElems: %u elemSize: %u initialTtimeoutUs: %ld timeoutUs: %ld",
132  numElems, elemSize, initialTtimeoutUs, timeoutUs);
133  qDebug("SoapySDROutputThread::run: start running loop");
134 
135  while (m_running)
136  {
137  int ret = m_dev->writeStream(stream, buffs.data(), numElems, flags, timeNs, timeoutUs);
138 
139  if (ret == SOAPY_SDR_TIMEOUT)
140  {
141  qWarning("SoapySDROutputThread::run: timeout: flags: %d timeNs: %lld timeoutUs: %ld", flags, timeNs, timeoutUs);
142  }
143  else if (ret == SOAPY_SDR_OVERFLOW)
144  {
145  qWarning("SoapySDROutputThread::run: overflow: flags: %d timeNs: %lld timeoutUs: %ld", flags, timeNs, timeoutUs);
146  }
147  else if (ret < 0)
148  {
149  qCritical("SoapySDROutputThread::run: Unexpected write stream error: %s", SoapySDR::errToStr(ret));
150  break;
151  }
152 
153  if (m_nbChannels > 1)
154  {
155  callbackMO(buffs, numElems); // size given in number of samples (1 item per sample)
156  }
157  else
158  {
159  switch (m_interpolatorType)
160  {
161  case Interpolator8:
162  callbackSO8((qint8*) buffs[0], numElems);
163  break;
164  case Interpolator12:
165  callbackSO12((qint16*) buffs[0], numElems);
166  break;
167  case Interpolator16:
168  callbackSO16((qint16*) buffs[0], numElems);
169  break;
170  case InterpolatorFloat:
171  default:
172  callbackSOIF((float*) buffs[0], numElems);
173  break;
174  }
175  }
176  }
177 
178  qDebug("SoapySDROutputThread::run: stop running loop");
179  m_dev->deactivateStream(stream);
180  m_dev->closeStream(stream);
181 
182  }
183  else
184  {
185  qWarning("SoapySDROutputThread::run: no channels or FIFO allocated. Aborting");
186  }
187 
188  m_running = false;
189 }
void callbackSO16(qint16 *buf, qint32 len, unsigned int channel=0)
QWaitCondition m_startWaiter
SoapySDR::Device * m_dev
void callbackSOIF(float *buf, qint32 len, unsigned int channel=0)
int32_t i
Definition: decimators.h:244
InterpolatorType m_interpolatorType
void callbackMO(std::vector< void *> &buffs, qint32 samplesPerChannel)
void callbackSO8(qint8 *buf, qint32 len, unsigned int channel=0)
void callbackSO12(qint16 *buf, qint32 len, unsigned int channel=0)
+ Here is the call graph for this function:

◆ setFifo()

void SoapySDROutputThread::setFifo ( unsigned int  channel,
SampleSourceFifo sampleFifo 
)

Definition at line 221 of file soapysdroutputthread.cpp.

References m_channels, m_nbChannels, and SoapySDROutputThread::Channel::m_sampleFifo.

Referenced by SoapySDROutput::applySettings(), getSampleRate(), SoapySDROutput::start(), and SoapySDROutput::stop().

222 {
223  if (channel < m_nbChannels) {
224  m_channels[channel].m_sampleFifo = sampleFifo;
225  }
226 }
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the caller graph for this function:

◆ setLog2Interpolation()

void SoapySDROutputThread::setLog2Interpolation ( unsigned int  channel,
unsigned int  log2_interp 
)

Definition at line 205 of file soapysdroutputthread.cpp.

References m_channels, SoapySDROutputThread::Channel::m_log2Interp, and m_nbChannels.

Referenced by SoapySDROutput::applySettings(), getNbChannels(), SoapySDROutput::start(), and SoapySDROutput::stop().

206 {
207  if (channel < m_nbChannels) {
208  m_channels[channel].m_log2Interp = log2_interp;
209  }
210 }
Channel * m_channels
Array of channels dynamically allocated for the given number of Tx channels.
+ Here is the caller graph for this function:

◆ setSampleRate()

void SoapySDROutputThread::setSampleRate ( unsigned int  sampleRate)
inline

Definition at line 47 of file soapysdroutputthread.h.

References m_sampleRate.

Referenced by SoapySDROutput::applySettings(), and SoapySDROutput::start().

47 { m_sampleRate = sampleRate; }
+ Here is the caller graph for this function:

◆ startWork()

void SoapySDROutputThread::startWork ( )

Definition at line 50 of file soapysdroutputthread.cpp.

References m_running, m_startWaiter, and m_startWaitMutex.

Referenced by SoapySDROutput::applySettings(), SoapySDROutput::start(), and SoapySDROutput::stop().

51 {
52  if (m_running) {
53  return;
54  }
55 
56  m_startWaitMutex.lock();
57  start();
58 
59  while(!m_running) {
60  m_startWaiter.wait(&m_startWaitMutex, 100);
61  }
62 
63  m_startWaitMutex.unlock();
64 }
QWaitCondition m_startWaiter
+ Here is the caller graph for this function:

◆ stopWork()

void SoapySDROutputThread::stopWork ( )

Definition at line 66 of file soapysdroutputthread.cpp.

References m_running.

Referenced by SoapySDROutput::applySettings(), SoapySDROutput::start(), SoapySDROutput::stop(), and ~SoapySDROutputThread().

67 {
68  if (!m_running) {
69  return;
70  }
71 
72  m_running = false;
73  wait();
74 }
+ Here is the caller graph for this function:

Member Data Documentation

◆ m_channels

Channel* SoapySDROutputThread::m_channels
private

Array of channels dynamically allocated for the given number of Tx channels.

Definition at line 85 of file soapysdroutputthread.h.

Referenced by callbackMO(), callbackSO12(), callbackSO16(), callbackSO8(), callbackSOIF(), getFifo(), getLog2Interpolation(), getNbFifos(), setFifo(), setLog2Interpolation(), SoapySDROutputThread(), and ~SoapySDROutputThread().

◆ m_dev

SoapySDR::Device* SoapySDROutputThread::m_dev
private

Definition at line 83 of file soapysdroutputthread.h.

Referenced by run().

◆ m_interpolatorType

InterpolatorType SoapySDROutputThread::m_interpolatorType
private

Definition at line 88 of file soapysdroutputthread.h.

Referenced by callbackMO(), and run().

◆ m_nbChannels

unsigned int SoapySDROutputThread::m_nbChannels
private

◆ m_running

bool SoapySDROutputThread::m_running
private

Definition at line 82 of file soapysdroutputthread.h.

Referenced by isRunning(), run(), startWork(), stopWork(), and ~SoapySDROutputThread().

◆ m_sampleRate

unsigned int SoapySDROutputThread::m_sampleRate
private

Definition at line 86 of file soapysdroutputthread.h.

Referenced by getSampleRate(), run(), and setSampleRate().

◆ m_startWaiter

QWaitCondition SoapySDROutputThread::m_startWaiter
private

Definition at line 81 of file soapysdroutputthread.h.

Referenced by run(), and startWork().

◆ m_startWaitMutex

QMutex SoapySDROutputThread::m_startWaitMutex
private

Definition at line 80 of file soapysdroutputthread.h.

Referenced by startWork().


The documentation for this class was generated from the following files: