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.
limesdroutputthread.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 <errno.h>
19 #include <algorithm>
20 
21 #include "limesdroutputthread.h"
22 #include "limesdroutputsettings.h"
23 
24 LimeSDROutputThread::LimeSDROutputThread(lms_stream_t* stream, SampleSourceFifo* sampleFifo, QObject* parent) :
25  QThread(parent),
26  m_running(false),
27  m_stream(stream),
28  m_sampleFifo(sampleFifo),
29  m_log2Interp(0)
30 {
31  std::fill(m_buf, m_buf + 2*LIMESDROUTPUT_BLOCKSIZE, 0);
32 }
33 
35 {
36  stopWork();
37 }
38 
40 {
41  if (m_running) return; // return if running already
42 
43  if (LMS_StartStream(m_stream) < 0) {
44  qCritical("LimeSDROutputThread::startWork: could not start stream");
45  } else {
46  usleep(50000);
47  qDebug("LimeSDROutputThread::startWork: stream started");
48  }
49 
50  m_startWaitMutex.lock();
51  start();
52  while(!m_running)
53  m_startWaiter.wait(&m_startWaitMutex, 100);
54  m_startWaitMutex.unlock();
55 }
56 
58 {
59  if (!m_running) return; // return if not running
60 
61  m_running = false;
62  wait();
63 
64  if (LMS_StopStream(m_stream) < 0) {
65  qCritical("LimeSDROutputThread::stopWork: could not stop stream");
66  } else {
67  usleep(50000);
68  qDebug("LimeSDROutputThread::stopWork: stream stopped");
69  }
70 }
71 
72 void LimeSDROutputThread::setLog2Interpolation(unsigned int log2_interp)
73 {
74  m_log2Interp = log2_interp;
75 }
76 
78 {
79  int res;
80 
81  lms_stream_meta_t metadata; //Use metadata for additional control over sample receive function behaviour
82  metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
83  metadata.waitForTimestamp = false; //Do not wait for specific timestamps
84 
85  m_running = true;
86  m_startWaiter.wakeAll();
87 
88  while (m_running)
89  {
91 
92  res = LMS_SendStream(m_stream, (void *) m_buf, LIMESDROUTPUT_BLOCKSIZE, &metadata, 1000000);
93 
94  if (res < 0)
95  {
96  qCritical("LimeSDROutputThread::run write error: %s", strerror(errno));
97  break;
98  }
99  else if (res != LIMESDROUTPUT_BLOCKSIZE)
100  {
101  qDebug("LimeSDROutputThread::run written %d/%d samples", res, LIMESDROUTPUT_BLOCKSIZE);
102  }
103  }
104 
105  m_running = false;
106 }
107 
108 // Interpolate according to specified log2 (ex: log2=4 => decim=16)
109 void LimeSDROutputThread::callback(qint16* buf, qint32 len)
110 {
111  SampleVector::iterator beginRead;
112  m_sampleFifo->readAdvance(beginRead, len/(1<<m_log2Interp));
113  beginRead -= len;
114 
115  if (m_log2Interp == 0)
116  {
117  m_interpolators.interpolate1(&beginRead, buf, len*2);
118  }
119  else
120  {
121  switch (m_log2Interp)
122  {
123  case 1:
124  m_interpolators.interpolate2_cen(&beginRead, buf, len*2);
125  break;
126  case 2:
127  m_interpolators.interpolate4_cen(&beginRead, buf, len*2);
128  break;
129  case 3:
130  m_interpolators.interpolate8_cen(&beginRead, buf, len*2);
131  break;
132  case 4:
133  m_interpolators.interpolate16_cen(&beginRead, buf, len*2);
134  break;
135  case 5:
136  m_interpolators.interpolate32_cen(&beginRead, buf, len*2);
137  break;
138  case 6:
139  m_interpolators.interpolate64_cen(&beginRead, buf, len*2);
140  break;
141  default:
142  break;
143  }
144  }
145 }
146 
qint16 m_buf[2 *LIMESDROUTPUT_BLOCKSIZE]
#define LIMESDROUTPUT_BLOCKSIZE
QWaitCondition m_startWaiter
void interpolate64_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
void setLog2Interpolation(unsigned int log2_ioterp)
void interpolate32_cen(SampleVector::iterator *it, T *buf, qint32 len, bool invertIQ=false)
LimeSDROutputThread(lms_stream_t *stream, SampleSourceFifo *sampleFifo, QObject *parent=0)
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)
SampleSourceFifo * m_sampleFifo
void readAdvance(SampleVector::iterator &readUntil, unsigned int nbSamples)
void callback(qint16 *buf, qint32 len)
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)
Interpolators< qint16, SDR_TX_SAMP_SZ, 12 > m_interpolators