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.
udpsource.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 <QDebug>
19 #include <QNetworkAccessManager>
20 #include <QNetworkReply>
21 #include <QBuffer>
22 
23 #include "SWGChannelSettings.h"
24 #include "SWGChannelReport.h"
25 #include "SWGUDPSourceReport.h"
26 
27 #include "device/deviceapi.h"
28 #include "dsp/upchannelizer.h"
30 #include "dsp/dspcommands.h"
31 #include "util/db.h"
32 
33 #include "udpsource.h"
34 #include "udpsourcemsg.h"
35 
40 
41 const QString UDPSource::m_channelIdURI = "sdrangel.channeltx.udpsource";
42 const QString UDPSource::m_channelId = "UDPSource";
43 
45  ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource),
46  m_deviceAPI(deviceAPI),
47  m_basebandSampleRate(48000),
48  m_outputSampleRate(48000),
49  m_inputFrequencyOffset(0),
50  m_squelch(1e-6),
51  m_spectrum(0),
52  m_spectrumEnabled(false),
53  m_spectrumChunkSize(2160),
54  m_spectrumChunkCounter(0),
55  m_magsq(1e-10),
56  m_movingAverage(16, 1e-10),
57  m_inMovingAverage(480, 1e-10),
58  m_sampleRateSum(0),
59  m_sampleRateAvgCounter(0),
60  m_levelCalcCount(0),
61  m_peakLevel(0.0f),
62  m_levelSum(0.0f),
63  m_levelNbSamples(480),
64  m_squelchOpen(false),
65  m_squelchOpenCount(0),
66  m_squelchCloseCount(0),
67  m_squelchThreshold(4800),
68  m_modPhasor(0.0f),
69  m_SSBFilterBufferIndex(0),
70  m_settingsMutex(QMutex::Recursive)
71 {
72  setObjectName(m_channelId);
73 
76  m_SSBFilterBuffer = new Complex[m_ssbFftLen>>1]; // filter returns data exactly half of its size
77 
80 
81  m_channelizer = new UpChannelizer(this);
85 
86  m_networkManager = new QNetworkAccessManager();
87  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
88 }
89 
91 {
92  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
93  delete m_networkManager;
96  delete m_threadedChannelizer;
97  delete m_channelizer;
98  delete m_SSBFilter;
99  delete[] m_SSBFilterBuffer;
100 }
101 
103 {
106 }
107 
109 {
110  m_udpHandler.stop();
111 }
112 
113 void UDPSource::pull(Sample& sample)
114 {
116  {
117  sample.m_real = 0.0f;
118  sample.m_imag = 0.0f;
119  initSquelch(false);
120  return;
121  }
122 
123  Complex ci;
124 
125  m_settingsMutex.lock();
126 
127  if (m_interpolatorDistance > 1.0f) // decimate
128  {
129  modulateSample();
130 
132  {
133  modulateSample();
134  }
135  }
136  else
137  {
139  {
140  modulateSample();
141  }
142  }
143 
145 
146  ci *= m_carrierNco.nextIQ(); // shift to carrier frequency
147 
148  m_settingsMutex.unlock();
149 
150  double magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
151  magsq /= (SDR_TX_SCALED*SDR_TX_SCALED);
152  m_movingAverage.feed(magsq);
154 
155  sample.m_real = (FixReal) ci.real();
156  sample.m_imag = (FixReal) ci.imag();
157 }
158 
160 {
161  if (m_settings.m_sampleFormat == UDPSourceSettings::FormatSnLE) // Linear I/Q transponding
162  {
163  Sample s;
164 
166 
167  uint64_t magsq = s.m_real * s.m_real + s.m_imag * s.m_imag;
170 
172 
173  if (m_squelchOpen)
174  {
178  }
179  else
180  {
181  m_modSample.real(0.0f);
182  m_modSample.imag(0.0f);
183  }
184  }
186  {
187  qint16 t;
188  readMonoSample(t);
189 
190  m_inMovingAverage.feed((t*t)/1073741824.0);
192 
194 
195  if (m_squelchOpen)
196  {
199  m_modSample.imag(sin(m_modPhasor) * 0.3162292f * SDR_TX_SCALEF * m_settings.m_gainOut);
201  }
202  else
203  {
204  m_modSample.real(0.0f);
205  m_modSample.imag(0.0f);
206  }
207  }
209  {
210  qint16 t;
211  readMonoSample(t);
214 
216 
217  if (m_squelchOpen)
218  {
219  m_modSample.real(((t / SDR_TX_SCALEF)*m_settings.m_amModFactor*m_settings.m_gainOut + 1.0f) * (SDR_TX_SCALEF/2)); // modulate and scale zero frequency carrier
220  m_modSample.imag(0.0f);
222  }
223  else
224  {
225  m_modSample.real(0.0f);
226  m_modSample.imag(0.0f);
227  }
228  }
230  {
231  qint16 t;
232  Complex c, ci;
233  fftfilt::cmplx *filtered;
234  int n_out = 0;
235 
236  readMonoSample(t);
239 
241 
242  if (m_squelchOpen)
243  {
244  ci.real((t / SDR_TX_SCALEF) * m_settings.m_gainOut);
245  ci.imag(0.0f);
246 
248 
249  if (n_out > 0)
250  {
251  memcpy((void *) m_SSBFilterBuffer, (const void *) filtered, n_out*sizeof(Complex));
253  }
254 
259 
261  }
262  else
263  {
264  m_modSample.real(0.0f);
265  m_modSample.imag(0.0f);
266  }
267  }
268  else
269  {
270  m_modSample.real(0.0f);
271  m_modSample.imag(0.0f);
272  initSquelch(false);
273  }
274 
276  {
277  Sample s;
278  s.m_real = (FixReal) m_modSample.real();
279  s.m_imag = (FixReal) m_modSample.imag();
280  m_sampleBuffer.push_back(s);
282  }
283  else if (m_spectrum)
284  {
285  m_spectrum->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false);
286  m_sampleBuffer.clear();
288  }
289 }
290 
292 {
294  {
295  m_peakLevel = std::max(std::fabs(m_peakLevel), sample);
296  m_levelSum += sample * sample;
298  }
299  else
300  {
301  qreal rmsLevel = m_levelSum > 0.0 ? sqrt(m_levelSum / m_levelNbSamples) : 0.0;
302  //qDebug("NFMMod::calculateLevel: %f %f", rmsLevel, m_peakLevel);
303  emit levelChanged(rmsLevel, m_peakLevel, m_levelNbSamples);
304  m_peakLevel = 0.0f;
305  m_levelSum = 0.0f;
306  m_levelCalcCount = 0;
307  }
308 }
309 
311 {
312  Real t = std::abs(sample);
313 
315  {
316  m_peakLevel = std::max(std::fabs(m_peakLevel), t);
317  m_levelSum += (t * t);
319  }
320  else
321  {
322  qreal rmsLevel = m_levelSum > 0.0 ? sqrt((m_levelSum/(SDR_TX_SCALED*SDR_TX_SCALED)) / m_levelNbSamples) : 0.0;
324  m_peakLevel = 0.0f;
325  m_levelSum = 0.0f;
326  m_levelCalcCount = 0;
327  }
328 }
329 
331 {
333  {
335  qDebug() << "UDPSource::handleMessage: MsgChannelizerNotification";
336 
338 
339  return true;
340  }
341  else if (MsgConfigureChannelizer::match(cmd))
342  {
344  qDebug() << "UDPSource::handleMessage: MsgConfigureChannelizer:"
345  << " sampleRate: " << cfg.getSampleRate()
346  << " centerFrequency: " << cfg.getCenterFrequency();
347 
349  cfg.getSampleRate(),
350  cfg.getCenterFrequency());
351 
352  return true;
353  }
354  else if (MsgConfigureUDPSource::match(cmd))
355  {
357  qDebug() << "UDPSource::handleMessage: MsgConfigureUDPSource";
358 
359  applySettings(cfg.getSettings(), cfg.getForce());
360 
361  return true;
362  }
364  {
367 
368  // exclude values too way out nominal sample rate (20%)
369  if ((newSampleRate < m_settings.m_inputSampleRate * 1.2) && (newSampleRate > m_settings.m_inputSampleRate * 0.8))
370  {
371  m_actualInputSampleRate = newSampleRate;
372 
373  if ((cfg.getRawDeltaRatio() > -0.05) && (cfg.getRawDeltaRatio() < 0.05))
374  {
376  {
379  }
380  }
381  else
382  {
383  m_sampleRateSum = 0.0;
385  }
386 
388  {
389  float avgRate = m_sampleRateSum / m_sampleRateAverageItems;
390  qDebug("UDPSource::handleMessage: MsgSampleRateCorrection: corr: %+.6f new rate: %.0f: avg rate: %.0f",
391  cfg.getCorrectionFactor(),
393  avgRate);
394  m_actualInputSampleRate = avgRate;
395  m_sampleRateSum = 0.0;
397  }
398 // else
399 // {
400 // qDebug("UDPSource::handleMessage: MsgSampleRateCorrection: corr: %+.6f new rate: %.0f",
401 // cfg.getCorrectionFactor(),
402 // m_actualInputSampleRate);
403 // }
404 
405  m_settingsMutex.lock();
407  m_interpolatorConsumed = false;
409  //m_interpolator.create(48, m_actualInputSampleRate, m_settings.m_rfBandwidth / 2.2, 3.0); // causes clicking: leaving at standard frequency
410  m_settingsMutex.unlock();
411  }
412 
413  return true;
414  }
415  else if (MsgUDPSourceSpectrum::match(cmd))
416  {
419  qDebug() << "UDPSource::handleMessage: MsgUDPSourceSpectrum: m_spectrumEnabled: " << m_spectrumEnabled;
420 
421  return true;
422  }
423  else if (MsgResetReadIndex::match(cmd))
424  {
425  m_settingsMutex.lock();
427  m_settingsMutex.unlock();
428 
429  qDebug() << "UDPSource::handleMessage: MsgResetReadIndex";
430 
431  return true;
432  }
433  else if (DSPSignalNotification::match(cmd))
434  {
435  return true;
436  }
437  else
438  {
439  if(m_spectrum != 0)
440  {
441  return m_spectrum->handleMessage(cmd);
442  }
443  else
444  {
445  return false;
446  }
447  }
448 }
449 
450 void UDPSource::setSpectrum(bool enabled)
451 {
452  Message* cmd = MsgUDPSourceSpectrum::create(enabled);
453  getInputMessageQueue()->push(cmd);
454 }
455 
457 {
459  getInputMessageQueue()->push(cmd);
460 }
461 
462 void UDPSource::applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force)
463 {
464  qDebug() << "UDPSource::applyChannelSettings:"
465  << " basebandSampleRate: " << basebandSampleRate
466  << " outputSampleRate: " << outputSampleRate
467  << " inputFrequencyOffset: " << inputFrequencyOffset;
468 
469  if ((inputFrequencyOffset != m_inputFrequencyOffset) ||
470  (outputSampleRate != m_outputSampleRate) || force)
471  {
472  m_settingsMutex.lock();
473  m_carrierNco.setFreq(inputFrequencyOffset, outputSampleRate);
474  m_settingsMutex.unlock();
475  }
476 
477  if (((outputSampleRate != m_outputSampleRate) && (!m_settings.m_autoRWBalance)) || force)
478  {
479  m_settingsMutex.lock();
481  m_interpolatorConsumed = false;
484  m_settingsMutex.unlock();
485  }
486 
487  m_basebandSampleRate = basebandSampleRate;
488  m_outputSampleRate = outputSampleRate;
489  m_inputFrequencyOffset = inputFrequencyOffset;
490 }
491 
492 void UDPSource::applySettings(const UDPSourceSettings& settings, bool force)
493 {
494  qDebug() << "UDPSource::applySettings:"
495  << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
496  << " m_sampleFormat: " << settings.m_sampleFormat
497  << " m_inputSampleRate: " << settings.m_inputSampleRate
498  << " m_rfBandwidth: " << settings.m_rfBandwidth
499  << " m_lowCutoff: " << settings.m_lowCutoff
500  << " m_fmDeviation: " << settings.m_fmDeviation
501  << " m_amModFactor: " << settings.m_amModFactor
502  << " m_udpAddressStr: " << settings.m_udpAddress
503  << " m_udpPort: " << settings.m_udpPort
504  << " m_channelMute: " << settings.m_channelMute
505  << " m_gainIn: " << settings.m_gainIn
506  << " m_gainOut: " << settings.m_gainOut
507  << " m_squelchGate: " << settings.m_squelchGate
508  << " m_squelch: " << settings.m_squelch << "dB"
509  << " m_squelchEnabled: " << settings.m_squelchEnabled
510  << " m_autoRWBalance: " << settings.m_autoRWBalance
511  << " m_stereoInput: " << settings.m_stereoInput
512  << " force: " << force;
513 
514  QList<QString> reverseAPIKeys;
515 
516  if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
517  reverseAPIKeys.append("inputFrequencyOffset");
518  }
519  if ((settings.m_sampleFormat != m_settings.m_sampleFormat) || force) {
520  reverseAPIKeys.append("sampleFormat");
521  }
522  if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force) {
523  reverseAPIKeys.append("inputSampleRate");
524  }
525  if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
526  reverseAPIKeys.append("rfBandwidth");
527  }
528  if ((settings.m_lowCutoff != m_settings.m_lowCutoff) || force) {
529  reverseAPIKeys.append("lowCutoff");
530  }
531  if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) {
532  reverseAPIKeys.append("fmDeviation");
533  }
534  if ((settings.m_amModFactor != m_settings.m_amModFactor) || force) {
535  reverseAPIKeys.append("amModFactor");
536  }
537  if ((settings.m_udpAddress != m_settings.m_udpAddress) || force) {
538  reverseAPIKeys.append("udpAddress");
539  }
540  if ((settings.m_udpPort != m_settings.m_udpPort) || force) {
541  reverseAPIKeys.append("udpPort");
542  }
543  if ((settings.m_channelMute != m_settings.m_channelMute) || force) {
544  reverseAPIKeys.append("channelMute");
545  }
546  if ((settings.m_gainIn != m_settings.m_gainIn) || force) {
547  reverseAPIKeys.append("gainIn");
548  }
549  if ((settings.m_gainOut != m_settings.m_gainOut) || force) {
550  reverseAPIKeys.append("gainOut");
551  }
552  if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) {
553  reverseAPIKeys.append("squelchGate");
554  }
555  if ((settings.m_squelch != m_settings.m_squelch) || force) {
556  reverseAPIKeys.append("squelch");
557  }
558  if ((settings.m_squelchEnabled != m_settings.m_squelchEnabled) || force) {
559  reverseAPIKeys.append("squelchEnabled");
560  }
561  if ((settings.m_autoRWBalance != m_settings.m_autoRWBalance) || force) {
562  reverseAPIKeys.append("autoRWBalance");
563  }
564  if ((settings.m_stereoInput != m_settings.m_stereoInput) || force) {
565  reverseAPIKeys.append("stereoInput");
566  }
567 
568  if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) ||
569  (settings.m_lowCutoff != m_settings.m_lowCutoff) ||
570  (settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force)
571  {
572  m_settingsMutex.lock();
574  m_interpolatorConsumed = false;
576  m_interpolator.create(48, settings.m_inputSampleRate, settings.m_rfBandwidth / 2.2, 3.0);
579  m_sampleRateSum = 0.0;
581  m_spectrumChunkSize = settings.m_inputSampleRate * 0.05; // 50 ms chunk
583  m_levelNbSamples = settings.m_inputSampleRate * 0.01; // every 10 ms
584  m_levelCalcCount = 0;
585  m_peakLevel = 0.0f;
586  m_levelSum = 0.0f;
588  m_inMovingAverage.resize(settings.m_inputSampleRate * 0.01, 1e-10); // 10 ms
589  m_squelchThreshold = settings.m_inputSampleRate * settings.m_squelchGate;
591  m_SSBFilter->create_filter(settings.m_lowCutoff / settings.m_inputSampleRate, settings.m_rfBandwidth / settings.m_inputSampleRate);
592  m_settingsMutex.unlock();
593  }
594 
595  if ((settings.m_squelch != m_settings.m_squelch) || force)
596  {
598  }
599 
600  if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
601  {
604  }
605 
606  if ((settings.m_udpAddress != m_settings.m_udpAddress) ||
607  (settings.m_udpPort != m_settings.m_udpPort) || force)
608  {
609  m_settingsMutex.lock();
611  m_settingsMutex.unlock();
612  }
613 
614  if ((settings.m_channelMute != m_settings.m_channelMute) || force)
615  {
616  if (!settings.m_channelMute) {
618  }
619  }
620 
621  if ((settings.m_autoRWBalance != m_settings.m_autoRWBalance) || force)
622  {
623  m_settingsMutex.lock();
625 
626  if (!settings.m_autoRWBalance)
627  {
629  m_interpolatorConsumed = false;
631  m_interpolator.create(48, settings.m_inputSampleRate, settings.m_rfBandwidth / 2.2, 3.0);
634  }
635 
636  m_settingsMutex.unlock();
637  }
638 
639  if (settings.m_useReverseAPI)
640  {
641  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
646  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
647  }
648 
649  m_settings = settings;
650 }
651 
652 QByteArray UDPSource::serialize() const
653 {
654  return m_settings.serialize();
655 }
656 
657 bool UDPSource::deserialize(const QByteArray& data)
658 {
659  if (m_settings.deserialize(data))
660  {
663  return true;
664  }
665  else
666  {
670  return false;
671  }
672 }
673 
676  QString& errorMessage)
677 {
678  (void) errorMessage;
680  response.getUdpSourceSettings()->init();
682  return 200;
683 }
684 
686  bool force,
687  const QStringList& channelSettingsKeys,
689  QString& errorMessage)
690 {
691  (void) errorMessage;
692  UDPSourceSettings settings = m_settings;
693  bool frequencyOffsetChanged = false;
694 
695  if (channelSettingsKeys.contains("sampleFormat")) {
697  }
698  if (channelSettingsKeys.contains("inputSampleRate")) {
700  }
701  if (channelSettingsKeys.contains("inputFrequencyOffset"))
702  {
704  frequencyOffsetChanged = true;
705  }
706  if (channelSettingsKeys.contains("rfBandwidth")) {
707  settings.m_rfBandwidth = response.getUdpSourceSettings()->getRfBandwidth();
708  }
709  if (channelSettingsKeys.contains("lowCutoff")) {
710  settings.m_lowCutoff = response.getUdpSourceSettings()->getLowCutoff();
711  }
712  if (channelSettingsKeys.contains("fmDeviation")) {
713  settings.m_fmDeviation = response.getUdpSourceSettings()->getFmDeviation();
714  }
715  if (channelSettingsKeys.contains("amModFactor")) {
716  settings.m_amModFactor = response.getUdpSourceSettings()->getAmModFactor();
717  }
718  if (channelSettingsKeys.contains("channelMute")) {
719  settings.m_channelMute = response.getUdpSourceSettings()->getChannelMute() != 0;
720  }
721  if (channelSettingsKeys.contains("gainIn")) {
722  settings.m_gainIn = response.getUdpSourceSettings()->getGainIn();
723  }
724  if (channelSettingsKeys.contains("gainOut")) {
725  settings.m_gainOut = response.getUdpSourceSettings()->getGainOut();
726  }
727  if (channelSettingsKeys.contains("squelch")) {
728  settings.m_squelch = response.getUdpSourceSettings()->getSquelch();
729  }
730  if (channelSettingsKeys.contains("squelchGate")) {
731  settings.m_squelchGate = response.getUdpSourceSettings()->getSquelchGate();
732  }
733  if (channelSettingsKeys.contains("squelchEnabled")) {
734  settings.m_squelchEnabled = response.getUdpSourceSettings()->getSquelchEnabled() != 0;
735  }
736  if (channelSettingsKeys.contains("autoRWBalance")) {
737  settings.m_autoRWBalance = response.getUdpSourceSettings()->getAutoRwBalance() != 0;
738  }
739  if (channelSettingsKeys.contains("stereoInput")) {
740  settings.m_stereoInput = response.getUdpSourceSettings()->getStereoInput() != 0;
741  }
742  if (channelSettingsKeys.contains("rgbColor")) {
743  settings.m_rgbColor = response.getUdpSourceSettings()->getRgbColor();
744  }
745  if (channelSettingsKeys.contains("udpAddress")) {
746  settings.m_udpAddress = *response.getUdpSourceSettings()->getUdpAddress();
747  }
748  if (channelSettingsKeys.contains("udpPort")) {
749  settings.m_udpPort = response.getUdpSourceSettings()->getUdpPort();
750  }
751  if (channelSettingsKeys.contains("title")) {
752  settings.m_title = *response.getUdpSourceSettings()->getTitle();
753  }
754  if (channelSettingsKeys.contains("useReverseAPI")) {
755  settings.m_useReverseAPI = response.getUdpSourceSettings()->getUseReverseApi() != 0;
756  }
757  if (channelSettingsKeys.contains("reverseAPIAddress")) {
759  }
760  if (channelSettingsKeys.contains("reverseAPIPort")) {
762  }
763  if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
765  }
766  if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
768  }
769 
770  if (frequencyOffsetChanged)
771  {
773  settings.m_inputSampleRate,
774  settings.m_inputFrequencyOffset);
775  m_inputMessageQueue.push(msgChan);
776  }
777 
780 
781  if (m_guiMessageQueue) // forward to GUI if any
782  {
783  MsgConfigureUDPSource *msgToGUI = MsgConfigureUDPSource::create(settings, force);
784  m_guiMessageQueue->push(msgToGUI);
785  }
786 
787  webapiFormatChannelSettings(response, settings);
788 
789  return 200;
790 }
791 
794  QString& errorMessage)
795 {
796  (void) errorMessage;
798  response.getUdpSourceReport()->init();
799  webapiFormatChannelReport(response);
800  return 200;
801 }
802 
804 {
805  response.getUdpSourceSettings()->setSampleFormat((int) settings.m_sampleFormat);
808  response.getUdpSourceSettings()->setRfBandwidth(settings.m_rfBandwidth);
809  response.getUdpSourceSettings()->setLowCutoff(settings.m_lowCutoff);
810  response.getUdpSourceSettings()->setFmDeviation(settings.m_fmDeviation);
811  response.getUdpSourceSettings()->setAmModFactor(settings.m_amModFactor);
812  response.getUdpSourceSettings()->setChannelMute(settings.m_channelMute ? 1 : 0);
813  response.getUdpSourceSettings()->setGainIn(settings.m_gainIn);
814  response.getUdpSourceSettings()->setGainOut(settings.m_gainOut);
815  response.getUdpSourceSettings()->setSquelch(settings.m_squelch);
816  response.getUdpSourceSettings()->setSquelchGate(settings.m_squelchGate);
817  response.getUdpSourceSettings()->setSquelchEnabled(settings.m_squelchEnabled ? 1 : 0);
818  response.getUdpSourceSettings()->setAutoRwBalance(settings.m_autoRWBalance ? 1 : 0);
819  response.getUdpSourceSettings()->setStereoInput(settings.m_stereoInput ? 1 : 0);
820  response.getUdpSourceSettings()->setRgbColor(settings.m_rgbColor);
821 
822  if (response.getUdpSourceSettings()->getUdpAddress()) {
823  *response.getUdpSourceSettings()->getUdpAddress() = settings.m_udpAddress;
824  } else {
825  response.getUdpSourceSettings()->setUdpAddress(new QString(settings.m_udpAddress));
826  }
827 
828  response.getUdpSourceSettings()->setUdpPort(settings.m_udpPort);
829 
830  if (response.getUdpSourceSettings()->getTitle()) {
831  *response.getUdpSourceSettings()->getTitle() = settings.m_title;
832  } else {
833  response.getUdpSourceSettings()->setTitle(new QString(settings.m_title));
834  }
835 
836  response.getUdpSourceSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
837 
838  if (response.getUdpSourceSettings()->getReverseApiAddress()) {
840  } else {
841  response.getUdpSourceSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
842  }
843 
847 }
848 
850 {
853  response.getUdpSourceReport()->setSquelch(m_squelchOpen ? 1 : 0);
856 }
857 
858 void UDPSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSourceSettings& settings, bool force)
859 {
861  swgChannelSettings->setDirection(1); // single source (Tx)
862  swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
863  swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
864  swgChannelSettings->setChannelType(new QString("UDPSource"));
865  swgChannelSettings->setUdpSourceSettings(new SWGSDRangel::SWGUDPSourceSettings());
866  SWGSDRangel::SWGUDPSourceSettings *swgUDPSourceSettings = swgChannelSettings->getUdpSourceSettings();
867 
868  // transfer data that has been modified. When force is on transfer all data except reverse API data
869 
870  if (channelSettingsKeys.contains("sampleFormat") || force) {
871  swgUDPSourceSettings->setSampleFormat((int) settings.m_sampleFormat);
872  }
873  if (channelSettingsKeys.contains("inputSampleRate") || force) {
874  swgUDPSourceSettings->setInputSampleRate(settings.m_inputSampleRate);
875  }
876  if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
877  swgUDPSourceSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
878  }
879  if (channelSettingsKeys.contains("rfBandwidth") || force) {
880  swgUDPSourceSettings->setRfBandwidth(settings.m_rfBandwidth);
881  }
882  if (channelSettingsKeys.contains("lowCutoff") || force) {
883  swgUDPSourceSettings->setLowCutoff(settings.m_lowCutoff);
884  }
885  if (channelSettingsKeys.contains("fmDeviation") || force) {
886  swgUDPSourceSettings->setFmDeviation(settings.m_fmDeviation);
887  }
888  if (channelSettingsKeys.contains("amModFactor") || force) {
889  swgUDPSourceSettings->setAmModFactor(settings.m_amModFactor);
890  }
891  if (channelSettingsKeys.contains("channelMute") || force) {
892  swgUDPSourceSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
893  }
894  if (channelSettingsKeys.contains("gainIn") || force) {
895  swgUDPSourceSettings->setGainIn(settings.m_gainIn);
896  }
897  if (channelSettingsKeys.contains("gainOut") || force) {
898  swgUDPSourceSettings->setGainOut(settings.m_gainOut);
899  }
900  if (channelSettingsKeys.contains("squelch") || force) {
901  swgUDPSourceSettings->setSquelch(settings.m_squelch);
902  }
903  if (channelSettingsKeys.contains("squelchGate") || force) {
904  swgUDPSourceSettings->setSquelchGate(settings.m_squelchGate);
905  }
906  if (channelSettingsKeys.contains("squelchEnabled") || force) {
907  swgUDPSourceSettings->setSquelchEnabled(settings.m_squelchEnabled ? 1 : 0);
908  }
909  if (channelSettingsKeys.contains("autoRWBalance") || force) {
910  swgUDPSourceSettings->setAutoRwBalance(settings.m_autoRWBalance ? 1 : 0);
911  }
912  if (channelSettingsKeys.contains("stereoInput") || force) {
913  swgUDPSourceSettings->setStereoInput(settings.m_stereoInput ? 1 : 0);
914  }
915  if (channelSettingsKeys.contains("rgbColor") || force) {
916  swgUDPSourceSettings->setRgbColor(settings.m_rgbColor);
917  }
918  if (channelSettingsKeys.contains("udpAddress") || force) {
919  swgUDPSourceSettings->setUdpAddress(new QString(settings.m_udpAddress));
920  }
921  if (channelSettingsKeys.contains("udpPort") || force) {
922  swgUDPSourceSettings->setUdpPort(settings.m_udpPort);
923  }
924  if (channelSettingsKeys.contains("title") || force) {
925  swgUDPSourceSettings->setTitle(new QString(settings.m_title));
926  }
927 
928  QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
929  .arg(settings.m_reverseAPIAddress)
930  .arg(settings.m_reverseAPIPort)
931  .arg(settings.m_reverseAPIDeviceIndex)
932  .arg(settings.m_reverseAPIChannelIndex);
933  m_networkRequest.setUrl(QUrl(channelSettingsURL));
934  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
935 
936  QBuffer *buffer=new QBuffer();
937  buffer->open((QBuffer::ReadWrite));
938  buffer->write(swgChannelSettings->asJson().toUtf8());
939  buffer->seek(0);
940 
941  // Always use PATCH to avoid passing reverse API settings
942  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
943 
944  delete swgChannelSettings;
945 }
946 
947 void UDPSource::networkManagerFinished(QNetworkReply *reply)
948 {
949  QNetworkReply::NetworkError replyError = reply->error();
950 
951  if (replyError)
952  {
953  qWarning() << "UDPSource::networkManagerFinished:"
954  << " error(" << (int) replyError
955  << "): " << replyError
956  << ": " << reply->errorString();
957  return;
958  }
959 
960  QString answer = reply->readAll();
961  answer.chop(1); // remove last \n
962  qDebug("UDPSource::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
963 }
float m_modPhasor
Phasor for FM modulation.
Definition: udpsource.h:241
virtual bool deserialize(const QByteArray &data)
Definition: udpsource.cpp:657
double getInMagSq() const
Definition: udpsource.h:136
void setOriginatorChannelIndex(qint32 originator_channel_index)
int m_basebandSampleRate
Definition: udpsource.h:200
int m_spectrumChunkCounter
Definition: udpsource.h:214
Complex nextIQ()
Return next complex sample.
Definition: nco.cpp:61
QNetworkRequest m_networkRequest
Definition: udpsource.h:247
bool decimate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:38
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
virtual int webapiSettingsPutPatch(bool force, const QStringList &channelSettingsKeys, SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: udpsource.cpp:685
Fixed< IntType, IntBits > cos(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2271
Complex * m_SSBFilterBuffer
Definition: udpsource.h:243
void setReverseApiChannelIndex(qint32 reverse_api_channel_index)
void setFmDeviation(qint32 fm_deviation)
static const QString m_channelId
Definition: udpsource.h:144
void applySettings(const UDPSourceSettings &settings, bool force=false)
Definition: udpsource.cpp:492
void feed(Type value)
Definition: movingaverage.h:24
void removeChannelSourceAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:181
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
void initSquelch(bool open)
Definition: udpsource.h:306
void setChannelSampleRate(qint32 channel_sample_rate)
virtual void stop()
Definition: udpsource.cpp:108
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
bool interpolate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:53
int m_inputFrequencyOffset
Definition: udpsource.h:202
Real m_squelch
Definition: udpsource.h:205
int getDeviceSetIndex() const
Definition: channelapi.h:89
static MsgResetReadIndex * create()
Definition: udpsource.h:184
static const QString m_channelIdURI
Definition: udpsource.h:143
const UDPSourceSettings & getSettings() const
Definition: udpsource.h:50
virtual void pull(Sample &sample)
Definition: udpsource.cpp:113
void removeChannelSource(ThreadedBasebandSampleSource *sink, int streamIndex=0)
Remove a channel source (Tx)
Definition: deviceapi.cpp:147
void setReverseApiAddress(QString *reverse_api_address)
static const int m_sampleRateAverageItems
Definition: udpsource.h:251
virtual int webapiReportGet(SWGSDRangel::SWGChannelReport &response, QString &errorMessage)
Definition: udpsource.cpp:792
void setSampleFormat(qint32 sample_format)
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setReverseApiPort(qint32 reverse_api_port)
SWGUDPSourceSettings * getUdpSourceSettings()
void setUdpAddress(QString *udp_address)
void networkManagerFinished(QNetworkReply *reply)
Definition: udpsource.cpp:947
int m_SSBFilterBufferIndex
Definition: udpsource.h:244
Real m_outputSampleRate
Definition: udpsource.h:201
Fixed< IntType, IntBits > abs(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2313
void setStereoInput(qint32 stereo_input)
BasebandSampleSink * m_spectrum
Definition: udpsource.h:210
Real m_interpolatorDistanceRemain
Definition: udpsource.h:218
UDPSourceSettings m_settings
Definition: udpsource.h:203
static const int m_ssbFftLen
Definition: udpsource.h:252
void setAutoRWBalance(bool autoRWBalance)
Complex m_modSample
Definition: udpsource.h:208
#define M_PI
Definition: rdsdemod.cpp:27
int m_squelchThreshold
Definition: udpsource.h:239
Type average() const
Definition: movingaverage.h:43
void setChannelType(QString *channel_type)
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)=0
void addChannelSource(ThreadedBasebandSampleSource *sink, int streamIndex=0)
Add a channel source (Tx)
Definition: deviceapi.cpp:138
QNetworkAccessManager * m_networkManager
Definition: udpsource.h:246
void setOriginatorDeviceSetIndex(qint32 originator_device_set_index)
QMutex m_settingsMutex
Definition: udpsource.h:249
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings &response, const UDPSourceSettings &settings)
Definition: udpsource.cpp:803
MovingAverage< double > m_inMovingAverage
Definition: udpsource.h:224
MovingAverage< double > m_movingAverage
Definition: udpsource.h:223
void setSpectrum(bool enabled)
Definition: udpsource.cpp:450
void setAmModFactor(float am_mod_factor)
void setBufferGauge(qint32 buffer_gauge)
std::complex< float > cmplx
Definition: fftfilt.h:21
void setInputSampleRate(float input_sample_rate)
double m_sampleRateSum
Definition: udpsource.h:228
double m_magsq
Definition: udpsource.h:221
Real m_squelch
squared magnitude
void readMonoSample(qint16 &t)
Definition: udpsource.h:322
void webapiReverseSendSettings(QList< QString > &channelSettingsKeys, const UDPSourceSettings &settings, bool force)
Definition: udpsource.cpp:858
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport &response)
Definition: udpsource.cpp:849
Real m_actualInputSampleRate
sample rate with UDP buffer skew compensation
Definition: udpsource.h:227
void setUseReverseApi(qint32 use_reverse_api)
void readSample(qint16 &t)
audio mono
int m_spectrumChunkSize
Definition: udpsource.h:213
#define SDR_TX_SCALEF
Definition: dsptypes.h:39
UDPSourceUDPHandler m_udpHandler
Definition: udpsource.h:226
virtual bool handleMessage(const Message &cmd)=0
Processing of a message. Returns true if message has actually been processed.
int32_t getBufferGauge() const
Definition: udpsource.h:137
int m_levelNbSamples
Definition: udpsource.h:234
int m_levelCalcCount
Definition: udpsource.h:231
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
double m_levelSum
Definition: udpsource.h:233
fftfilt * m_SSBFilter
Complex filter for SSB modulation.
Definition: udpsource.h:242
bool m_squelchOpen
Definition: udpsource.h:236
void configureUDPLink(const QString &address, quint16 port)
void setSquelchEnabled(qint32 squelch_enabled)
void create_filter(float f1, float f2)
Definition: fftfilt.cpp:107
virtual ~UDPSource()
Definition: udpsource.cpp:90
virtual int webapiSettingsGet(SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: udpsource.cpp:674
bool m_spectrumEnabled
Definition: udpsource.h:211
FixReal m_real
Definition: dsptypes.h:64
Fixed< IntType, IntBits > sin(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2265
void setInputPowerDb(float input_power_db)
static bool match(const Message *message)
Definition: message.cpp:45
QByteArray serialize() const
void setFreq(Real freq, Real sampleRate)
Definition: nco.cpp:49
bool deserialize(const QByteArray &data)
Fixed< IntType, IntBits > sqrt(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2283
uint16_t m_reverseAPIDeviceIndex
NCO m_carrierNco
Definition: udpsource.h:207
bool m_interpolatorConsumed
Definition: udpsource.h:219
virtual QString asJson() override
void resetReadIndex()
Definition: udpsource.cpp:456
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
Definition: udpsource.cpp:330
int m_sampleRateAvgCounter
Definition: udpsource.h:229
DeviceAPI * m_deviceAPI
Definition: udpsource.h:196
void setInputFrequencyOffset(qint64 input_frequency_offset)
void setAutoRwBalance(qint32 auto_rw_balance)
UDPSource(DeviceAPI *deviceAPI)
Definition: udpsource.cpp:44
static MsgUDPSourceSpectrum * create(bool enabled)
Definition: udpsource.h:165
uint16_t m_reverseAPIChannelIndex
virtual void start()
Definition: udpsource.cpp:102
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
void applyChannelSettings(int basebandSampleRate, int outputSampleRate, int inputFrequencyOffset, bool force=false)
Definition: udpsource.cpp:462
double getMagSq() const
Definition: udpsource.h:135
Real m_interpolatorDistance
Definition: udpsource.h:217
void resizeBuffer(float sampleRate)
Interpolator m_interpolator
Definition: udpsource.h:216
int runSSB(const cmplx &in, cmplx **out, bool usb, bool getDC=true)
Definition: fftfilt.cpp:284
SWGUDPSourceReport * getUdpSourceReport()
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples)
Real m_squelchGate
seconds
double m_inMagsq
Definition: udpsource.h:222
FixReal m_imag
Definition: dsptypes.h:65
SampleFormat m_sampleFormat
ThreadedBasebandSampleSource * m_threadedChannelizer
Definition: udpsource.h:197
void addChannelSourceAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:174
SampleVector m_sampleBuffer
Definition: udpsource.h:212
Real m_peakLevel
Definition: udpsource.h:232
void calculateSquelch(double value)
Definition: udpsource.h:264
void modulateSample()
Definition: udpsource.cpp:159
void setChannelPowerDb(float channel_power_db)
int getIndexInDeviceSet() const
Definition: channelapi.h:87
std::complex< Real > Complex
Definition: dsptypes.h:43
UpChannelizer * m_channelizer
Definition: udpsource.h:198
void setChannelMute(qint32 channel_mute)
void setFeedbackMessageQueue(MessageQueue *messageQueue)
float Real
Definition: dsptypes.h:42
#define SDR_TX_SCALED
Definition: dsptypes.h:40
void resize(int historySize, Type initial)
Definition: movingaverage.h:16
static double powerFromdB(double powerdB)
Definition: db.cpp:36
qint16 FixReal
Definition: dsptypes.h:35
T max(const T &x, const T &y)
Definition: framework.h:446
void setUdpSourceReport(SWGUDPSourceReport *udp_source_report)
void calculateLevel(Real sample)
Definition: udpsource.cpp:291
static MsgConfigureUDPSource * create(const UDPSourceSettings &settings, bool force)
Definition: udpsource.h:53
virtual QByteArray serialize() const
Definition: udpsource.cpp:652
void setUdpSourceSettings(SWGUDPSourceSettings *udp_source_settings)
static MsgConfigureChannelizer * create(int sampleRate, int centerFrequency)
Definition: udpsource.h:77
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
unsigned __int64 uint64_t
Definition: rtptypes_win.h:48