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.
remoteinputudphandler.cpp
Go to the documentation of this file.
1 // Copyright (C) 2016 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 <QUdpSocket>
19 #include <QDebug>
20 #include <QTimer>
21 
22 #include "dsp/dspcommands.h"
23 #include "dsp/dspengine.h"
24 #include "device/deviceapi.h"
25 
26 #include "remoteinputudphandler.h"
27 #include "remoteinput.h"
28 
30  m_deviceAPI(deviceAPI),
31  m_masterTimer(deviceAPI->getMasterTimer()),
32  m_masterTimerConnected(false),
33  m_running(false),
34  m_rateDivider(1000/REMOTEINPUT_THROTTLE_MS),
35  m_dataSocket(0),
36  m_dataAddress(QHostAddress::LocalHost),
37  m_remoteAddress(QHostAddress::LocalHost),
38  m_dataPort(9090),
39  m_dataConnected(false),
40  m_udpBuf(0),
41  m_udpReadBytes(0),
42  m_sampleFifo(sampleFifo),
43  m_samplerate(0),
44  m_centerFrequency(0),
45  m_tv_msec(0),
46  m_outputMessageQueueToGUI(0),
47  m_tickCount(0),
48  m_samplesCount(0),
49  m_timer(0),
50  m_throttlems(REMOTEINPUT_THROTTLE_MS),
51  m_readLengthSamples(0),
52  m_readLength(0),
53  m_converterBuffer(0),
54  m_converterBufferNbSamples(0),
55  m_throttleToggle(false),
56  m_autoCorrBuffer(true)
57 {
58  m_udpBuf = new char[RemoteUdpSize];
59 
60 #ifdef USE_INTERNAL_TIMER
61 #warning "Uses internal timer"
62  m_timer = new QTimer();
63  m_timer->start(50);
64  m_throttlems = m_timer->interval();
65 #else
66  m_throttlems = m_masterTimer.interval();
67 #endif
68  m_rateDivider = 1000 / m_throttlems;
69 }
70 
72 {
73  stop();
74  delete[] m_udpBuf;
75  if (m_converterBuffer) { delete[] m_converterBuffer; }
76 #ifdef USE_INTERNAL_TIMER
77  if (m_timer) {
78  delete m_timer;
79  }
80 #endif
81 }
82 
84 {
85  qDebug("RemoteInputUDPHandler::start");
86 
87  if (m_running) {
88  return;
89  }
90 
91  if (!m_dataSocket)
92  {
93  m_dataSocket = new QUdpSocket(this);
94  }
95 
96  if (!m_dataConnected)
97  {
98  connect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead())); //, Qt::QueuedConnection);
99 
101  {
102  qDebug("RemoteInputUDPHandler::start: bind data socket to %s:%d", m_dataAddress.toString().toStdString().c_str(), m_dataPort);
103  m_dataConnected = true;
104  }
105  else
106  {
107  qWarning("RemoteInputUDPHandler::start: cannot bind data port %d", m_dataPort);
108  disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()));
109  m_dataConnected = false;
110  }
111  }
112 
113  m_elapsedTimer.start();
114  m_running = true;
115 }
116 
118 {
119  qDebug("RemoteInputUDPHandler::stop");
120 
121  if (!m_running) {
122  return;
123  }
124 
125  disconnectTimer();
126 
127  if (m_dataConnected)
128  {
129  m_dataConnected = false;
130  disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()));
131  }
132 
133  if (m_dataSocket)
134  {
135  delete m_dataSocket;
136  m_dataSocket = 0;
137  }
138 
139  m_centerFrequency = 0;
140  m_samplerate = 0;
141  m_running = false;
142 }
143 
144 void RemoteInputUDPHandler::configureUDPLink(const QString& address, quint16 port)
145 {
146  qDebug("RemoteInputUDPHandler::configureUDPLink: %s:%d", address.toStdString().c_str(), port);
147  bool addressOK = m_dataAddress.setAddress(address);
148 
149  if (!addressOK)
150  {
151  qWarning("RemoteInputUDPHandler::configureUDPLink: invalid address %s. Set to localhost.", address.toStdString().c_str());
152  m_dataAddress = QHostAddress::LocalHost;
153  }
154 
155  m_dataPort = port;
156  stop();
157  start();
158 }
159 
161 {
162  m_udpReadBytes = 0;
163 
164  while (m_dataSocket->hasPendingDatagrams() && m_dataConnected)
165  {
166  qint64 pendingDataSize = m_dataSocket->pendingDatagramSize();
167  m_udpReadBytes += m_dataSocket->readDatagram(&m_udpBuf[m_udpReadBytes], pendingDataSize, &m_remoteAddress, 0);
168 
169  if (m_udpReadBytes == RemoteUdpSize) {
170  processData();
171  m_udpReadBytes = 0;
172  }
173  }
174 }
175 
177 {
180  bool change = false;
181 
183 
184  if (m_centerFrequency != metaData.m_centerFrequency)
185  {
187  change = true;
188  }
189 
190  if (m_samplerate != metaData.m_sampleRate)
191  {
192  m_samplerate = metaData.m_sampleRate;
193  change = true;
194  }
195 
196  if (change && (m_samplerate != 0))
197  {
198  qDebug("RemoteInputUDPHandler::processData: m_samplerate: %u S/s m_centerFrequency: %lu Hz", m_samplerate, m_centerFrequency);
199 
200  DSPSignalNotification *notif = new DSPSignalNotification(m_samplerate, m_centerFrequency); // Frequency in Hz for the DSP engine
202 
204  {
206  m_samplerate,
207  m_centerFrequency, // Frequency in Hz for the GUI
208  m_tv_msec);
209 
211  }
212 
213  connectTimer();
214  }
215 }
216 
218 {
220  {
221  qDebug() << "RemoteInputUDPHandler::connectTimer";
222 #ifdef USE_INTERNAL_TIMER
223 #warning "Uses internal timer"
224  connect(m_timer, SIGNAL(timeout()), this, SLOT(tick()));
225 #else
226  connect(&m_masterTimer, SIGNAL(timeout()), this, SLOT(tick()));
227 #endif
228  m_masterTimerConnected = true;
229  }
230 }
231 
233 {
235  {
236  qDebug() << "RemoteInputUDPHandler::disconnectTimer";
237 #ifdef USE_INTERNAL_TIMER
238 #warning "Uses internal timer"
239  disconnect(m_timer, SIGNAL(timeout()), this, SLOT(tick()));
240 #else
241  disconnect(&m_masterTimer, SIGNAL(timeout()), this, SLOT(tick()));
242 #endif
243  m_masterTimerConnected = false;
244  }
245 }
246 
248 {
249  // auto throttling
250  int throttlems = m_elapsedTimer.restart();
251 
252  if (throttlems != m_throttlems)
253  {
254  m_throttlems = throttlems;
257  }
258 
259  if (m_autoCorrBuffer)
260  {
262  // Eliminate negative or excessively high values
266  }
267 
269  m_readLength = m_readLengthSamples * (metaData.m_sampleBytes & 0xF) * 2;
270 
271  if ((metaData.m_sampleBits == 16) && (SDR_RX_SAMP_SZ == 24)) // 16 -> 24 bits
272  {
274  {
275  if (m_converterBuffer) { delete[] m_converterBuffer; }
277  }
278 
280 
281  for (int is = 0; is < m_readLengthSamples; is++)
282  {
283  m_converterBuffer[2*is] = ((int16_t*)buf)[2*is]; // I
284  m_converterBuffer[2*is]<<=8;
285  m_converterBuffer[2*is+1] = ((int16_t*)buf)[2*is+1]; // Q
286  m_converterBuffer[2*is+1]<<=8;
287  }
288 
289  m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
290  }
291  else if ((metaData.m_sampleBits == 24) && (SDR_RX_SAMP_SZ == 16)) // 24 -> 16 bits
292  {
294  {
295  if (m_converterBuffer) { delete[] m_converterBuffer; }
297  }
298 
300 
301  for (int is = 0; is < m_readLengthSamples; is++)
302  {
303  m_converterBuffer[is] = ((int32_t *)buf)[2*is+1]>>8; // Q -> MSB
304  m_converterBuffer[is] <<=16;
305  m_converterBuffer[is] += ((int32_t *)buf)[2*is]>>8; // I -> LSB
306  }
307 
308  m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
309  }
310  else if ((metaData.m_sampleBits == 16) || (metaData.m_sampleBits == 24)) // same sample size and valid size
311  {
312  // read samples directly feeding the SampleFifo (no callback)
315  }
316  else // invalid size
317  {
318  qWarning("RemoteInputUDPHandler::tick: unexpected sample size in stream: %d bits", (int) metaData.m_sampleBits);
319  }
320 
322  {
323  m_tickCount++;
324  }
325  else
326  {
327  m_tickCount = 0;
328 
330  {
331  int framesDecodingStatus;
332  int minNbBlocks = m_remoteInputBuffer.getMinNbBlocks();
333  int minNbOriginalBlocks = m_remoteInputBuffer.getMinOriginalBlocks();
334  int nbOriginalBlocks = m_remoteInputBuffer.getCurrentMeta().m_nbOriginalBlocks;
338 
339  //framesDecodingStatus = (minNbOriginalBlocks == nbOriginalBlocks ? 2 : (minNbOriginalBlocks < nbOriginalBlocks - nbFECblocks ? 0 : 1));
340  if (minNbBlocks < nbOriginalBlocks) {
341  framesDecodingStatus = 0;
342  } else if (minNbBlocks < nbOriginalBlocks + nbFECblocks) {
343  framesDecodingStatus = 1;
344  } else {
345  framesDecodingStatus = 2;
346  }
347 
349  m_tv_msec,
352  framesDecodingStatus,
353  minNbBlocks == nbOriginalBlocks + nbFECblocks,
354  minNbBlocks,
355  minNbOriginalBlocks,
360  nbOriginalBlocks,
361  nbFECblocks,
362  sampleBits,
363  sampleBytes);
364 
366  }
367  }
368 }
short int16_t
Definition: rtptypes_win.h:43
uint32_t m_sampleRate
12 sample rate in Hz
SampleSinkFifo * m_sampleFifo
void push(Message *message, bool emitSignal=true)
Push message onto queue.
uint64_t getTVOutMSec() const
uint write(const quint8 *data, uint count)
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
uint8_t * readData(int32_t length)
Read data from buffer.
static MsgReportRemoteInputStreamTiming * create(uint64_t tv_msec, float bufferLenSec, int32_t bufferGauge, int framesDecodingStatus, bool allBlocksReceived, int minNbBlocks, int minNbOriginalBlocks, int maxNbRecovery, float avgNbBlocks, float avgNbOriginalBlocks, float avgNbRecovery, int nbOriginalBlocksPerFrame, int nbFECBlocksPerFrame, int sampleBits, int sampleBytes)
Definition: remoteinput.h:149
RemoteInputBuffer m_remoteInputBuffer
float getAvgNbRecovery() const
const RemoteMetaDataFEC & getCurrentMeta() const
float getAvgNbBlocks() const
#define SDR_RX_SAMP_SZ
Definition: dsptypes.h:32
#define REMOTEINPUT_THROTTLE_MS
uint8_t m_sampleBytes
13 4 LSB: number of bytes per sample (2 or 4)
unsigned char uint8_t
Definition: rtptypes_win.h:42
int32_t getRWBalanceCorrection() const
uint8_t m_nbFECBlocks
16 number of blocks carrying FEC
float getBufferLengthInSecs() const
uint8_t m_sampleBits
14 number of effective bits per sample (deprecated)
int int32_t
Definition: rtptypes_win.h:45
float getAvgOriginalBlocks() const
void configureUDPLink(const QString &address, quint16 port)
void writeData(char *array)
Write data into buffer.
uint8_t m_nbOriginalBlocks
15 number of blocks with original (protected) data
RemoteInputUDPHandler(SampleSinkFifo *sampleFifo, DeviceAPI *deviceAPI)
static MsgReportRemoteInputStreamData * create(int sampleRate, quint64 centerFrequency, uint64_t tv_msec)
Definition: remoteinput.h:111
MessageQueue * m_outputMessageQueueToGUI
uint64_t m_centerFrequency
8 center frequency in kHz
int32_t getBufferGauge() const