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.
ssbdemod.cpp
Go to the documentation of this file.
1 // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
3 // written by Christian Daniel //
4 // (c) 2014 Modified by John Greb
5 // //
6 // This program is free software; you can redistribute it and/or modify //
7 // it under the terms of the GNU General Public License as published by //
8 // the Free Software Foundation as version 3 of the License, or //
9 // (at your option) any later version. //
10 // //
11 // This program is distributed in the hope that it will be useful, //
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
14 // GNU General Public License V3 for more details. //
15 // //
16 // You should have received a copy of the GNU General Public License //
17 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
19 
20 
21 #include <stdio.h>
22 
23 #include <QTime>
24 #include <QDebug>
25 #include <QNetworkAccessManager>
26 #include <QNetworkReply>
27 #include <QBuffer>
28 
29 #include "SWGChannelSettings.h"
30 #include "SWGSSBDemodSettings.h"
31 #include "SWGChannelReport.h"
32 #include "SWGSSBDemodReport.h"
33 
34 #include "audio/audiooutput.h"
35 #include "dsp/dspengine.h"
36 #include "dsp/downchannelizer.h"
38 #include "dsp/dspcommands.h"
39 #include "device/deviceapi.h"
40 #include "util/db.h"
41 
42 #include "ssbdemod.h"
43 
47 
48 const QString SSBDemod::m_channelIdURI = "sdrangel.channel.ssbdemod";
49 const QString SSBDemod::m_channelId = "SSBDemod";
50 
52  ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
53  m_deviceAPI(deviceAPI),
54  m_audioBinaual(false),
55  m_audioFlipChannels(false),
56  m_dsb(false),
57  m_audioMute(false),
58  m_agc(12000, agcTarget, 1e-2),
59  m_agcActive(false),
60  m_agcClamping(false),
61  m_agcNbSamples(12000),
62  m_agcPowerThreshold(1e-2),
63  m_agcThresholdGate(0),
64  m_squelchDelayLine(2*48000),
65  m_audioActive(false),
66  m_sampleSink(0),
67  m_audioFifo(24000),
68  m_settingsMutex(QMutex::Recursive)
69 {
70  setObjectName(m_channelId);
71 
72  m_Bandwidth = 5000;
73  m_LowCutoff = 300;
74  m_volume = 2.0;
75  m_spanLog2 = 3;
76  m_inputSampleRate = 48000;
78 
81 
82  m_audioBuffer.resize(1<<14);
85  m_sum = 0;
86 
87  m_usb = true;
88  m_magsq = 0.0f;
89  m_magsqSum = 0.0f;
90  m_magsqPeak = 0.0f;
91  m_magsqCount = 0;
92 
95 
98 
100  applySettings(m_settings, true);
101 
102  m_channelizer = new DownChannelizer(this);
106 
107  m_networkManager = new QNetworkAccessManager();
108  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
109 }
110 
112 {
113  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
114  delete m_networkManager;
116 
119  delete m_threadedChannelizer;
120  delete m_channelizer;
121  delete SSBFilter;
122  delete DSBFilter;
123 }
124 
126  Real Bandwidth,
127  Real LowCutoff,
128  Real volume,
129  int spanLog2,
130  bool audioBinaural,
131  bool audioFlipChannel,
132  bool dsb,
133  bool audioMute,
134  bool agc,
135  bool agcClamping,
136  int agcTimeLog2,
137  int agcPowerThreshold,
138  int agcThresholdGate)
139 {
141  Bandwidth,
142  LowCutoff,
143  volume,
144  spanLog2,
145  audioBinaural,
146  audioFlipChannel,
147  dsb,
148  audioMute,
149  agc,
150  agcClamping,
151  agcTimeLog2,
152  agcPowerThreshold,
153  agcThresholdGate);
154  messageQueue->push(cmd);
155 }
156 
157 void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
158 {
159  (void) positiveOnly;
160  Complex ci;
161  m_settingsMutex.lock();
162 
163  for(SampleVector::const_iterator it = begin; it < end; ++it)
164  {
165  Complex c(it->real(), it->imag());
166  c *= m_nco.nextIQ();
167 
168  if (m_interpolatorDistance < 1.0f) // interpolate
169  {
171  {
172  processOneSample(ci);
174  }
175  }
176  else
177  {
179  {
180  processOneSample(ci);
182  }
183  }
184  }
185 
186  m_settingsMutex.unlock();
187 }
188 
190 {
191  fftfilt::cmplx *sideband;
192  int n_out = 0;
193  int decim = 1<<(m_spanLog2 - 1);
194  unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
195 
196  if (m_dsb) {
197  n_out = DSBFilter->runDSB(ci, &sideband);
198  } else {
199  n_out = SSBFilter->runSSB(ci, &sideband, m_usb);
200  }
201 
202  for (int i = 0; i < n_out; i++)
203  {
204  // Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
205  // smart decimation with bit gain using float arithmetic (23 bits significand)
206 
207  m_sum += sideband[i];
208 
209  if (!(m_undersampleCount++ & decim_mask))
210  {
211  Real avgr = m_sum.real() / decim;
212  Real avgi = m_sum.imag() / decim;
213  m_magsq = (avgr * avgr + avgi * avgi) / (SDR_RX_SCALED*SDR_RX_SCALED);
214 
215  m_magsqSum += m_magsq;
216 
217  if (m_magsq > m_magsqPeak)
218  {
220  }
221 
222  m_magsqCount++;
223 
224  if (!m_dsb & !m_usb)
225  { // invert spectrum for LSB
226  m_sampleBuffer.push_back(Sample(avgi, avgr));
227  }
228  else
229  {
230  m_sampleBuffer.push_back(Sample(avgr, avgi));
231  }
232 
233  m_sum.real(0.0);
234  m_sum.imag(0.0);
235  }
236 
237  float agcVal = m_agcActive ? m_agc.feedAndGetValue(sideband[i]) : 0.1;
239  m_audioActive = delayedSample.real() != 0.0;
240  m_squelchDelayLine.write(sideband[i]*agcVal);
241 
242  if (m_audioMute)
243  {
246  }
247  else
248  {
249  fftfilt::cmplx z = m_agcActive ? delayedSample * m_agc.getStepValue() : delayedSample;
250 
251  if (m_audioBinaual)
252  {
254  {
255  m_audioBuffer[m_audioBufferFill].r = (qint16)(z.imag() * m_volume);
256  m_audioBuffer[m_audioBufferFill].l = (qint16)(z.real() * m_volume);
257  }
258  else
259  {
260  m_audioBuffer[m_audioBufferFill].r = (qint16)(z.real() * m_volume);
261  m_audioBuffer[m_audioBufferFill].l = (qint16)(z.imag() * m_volume);
262  }
263  }
264  else
265  {
266  Real demod = (z.real() + z.imag()) * 0.7;
267  qint16 sample = (qint16)(demod * m_volume);
268  m_audioBuffer[m_audioBufferFill].l = sample;
269  m_audioBuffer[m_audioBufferFill].r = sample;
270  }
271  }
272 
274 
275  if (m_audioBufferFill >= m_audioBuffer.size())
276  {
277  uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
278 
279  if (res != m_audioBufferFill)
280  {
281  qDebug("SSBDemod::feed: %u/%u samples written", res, m_audioBufferFill);
282  }
283 
284  m_audioBufferFill = 0;
285  }
286  }
287 
288  uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
289 
290  if (res != m_audioBufferFill)
291  {
292  qDebug("SSBDemod::feed: %u/%u tail samples written", res, m_audioBufferFill);
293  }
294 
295  m_audioBufferFill = 0;
296 
297  if (m_sampleSink != 0)
298  {
300  }
301 
302  m_sampleBuffer.clear();
303 
304 }
305 
307 {
309 }
310 
312 {
313 }
314 
316 {
318  {
320  qDebug("SSBDemod::handleMessage: MsgChannelizerNotification: m_sampleRate");
321 
323 
324  return true;
325  }
326  else if (MsgConfigureChannelizer::match(cmd))
327  {
329  qDebug() << "SSBDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
330  << " centerFrequency: " << cfg.getCenterFrequency();
331 
333  cfg.getSampleRate(),
334  cfg.getCenterFrequency());
335 
336  return true;
337  }
338  else if (MsgConfigureSSBDemod::match(cmd))
339  {
341  qDebug("SSBDemod::handleMessage: MsgConfigureSSBDemod");
342 
343  applySettings(cfg.getSettings(), cfg.getForce());
344 
345  return true;
346  }
348  {
350  const QThread *thread = cfg.getThread();
351  qDebug("SSBDemod::handleMessage: BasebandSampleSink::MsgThreadedSink: %p", thread);
352  return true;
353  }
354  else if (DSPConfigureAudio::match(cmd))
355  {
356  DSPConfigureAudio& cfg = (DSPConfigureAudio&) cmd;
357  uint32_t sampleRate = cfg.getSampleRate();
358 
359  qDebug() << "SSBDemod::handleMessage: DSPConfigureAudio:"
360  << " sampleRate: " << sampleRate;
361 
362  if (sampleRate != m_audioSampleRate) {
363  applyAudioSampleRate(sampleRate);
364  }
365 
366  return true;
367  }
368  else if (DSPSignalNotification::match(cmd))
369  {
370  return true;
371  }
372  else
373  {
374  if(m_sampleSink != 0)
375  {
376  return m_sampleSink->handleMessage(cmd);
377  }
378  else
379  {
380  return false;
381  }
382  }
383 }
384 
385 void SSBDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force)
386 {
387  qDebug() << "SSBDemod::applyChannelSettings:"
388  << " inputSampleRate: " << inputSampleRate
389  << " inputFrequencyOffset: " << inputFrequencyOffset;
390 
391  if ((m_inputFrequencyOffset != inputFrequencyOffset) ||
392  (m_inputSampleRate != inputSampleRate) || force)
393  {
394  m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
395  }
396 
397  if ((m_inputSampleRate != inputSampleRate) || force)
398  {
399  m_settingsMutex.lock();
400  Real interpolatorBandwidth = (m_Bandwidth * 1.5f) > inputSampleRate ? inputSampleRate : (m_Bandwidth * 1.5f);
401  m_interpolator.create(16, inputSampleRate, interpolatorBandwidth, 2.0f);
403  m_interpolatorDistance = (Real) inputSampleRate / (Real) m_audioSampleRate;
404  m_settingsMutex.unlock();
405  }
406 
407  m_inputSampleRate = inputSampleRate;
408  m_inputFrequencyOffset = inputFrequencyOffset;
409 }
410 
411 void SSBDemod::applyAudioSampleRate(int sampleRate)
412 {
413  qDebug("SSBDemod::applyAudioSampleRate: %d", sampleRate);
414 
416  sampleRate, m_settings.m_inputFrequencyOffset);
417  m_inputMessageQueue.push(channelConfigMsg);
418 
419  m_settingsMutex.lock();
420 
421  Real interpolatorBandwidth = (m_Bandwidth * 1.5f) > m_inputSampleRate ? m_inputSampleRate : (m_Bandwidth * 1.5f);
422  m_interpolator.create(16, m_inputSampleRate, interpolatorBandwidth, 2.0f);
425 
426  SSBFilter->create_filter(m_LowCutoff / (float) sampleRate, m_Bandwidth / (float) sampleRate);
427  DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) sampleRate);
428 
429  int agcNbSamples = (sampleRate / 1000) * (1<<m_settings.m_agcTimeLog2);
430  int agcThresholdGate = (sampleRate / 1000) * m_settings.m_agcThresholdGate; // ms
431 
432  if (m_agcNbSamples != agcNbSamples)
433  {
434  m_agc.resize(agcNbSamples, agcNbSamples/2, agcTarget);
435  m_agc.setStepDownDelay(agcNbSamples);
436  m_agcNbSamples = agcNbSamples;
437  }
438 
439  if (m_agcThresholdGate != agcThresholdGate)
440  {
441  m_agc.setGate(agcThresholdGate);
442  m_agcThresholdGate = agcThresholdGate;
443  }
444 
445  m_audioFifo.setSize(sampleRate);
446 
447  m_settingsMutex.unlock();
448 
449  m_audioSampleRate = sampleRate;
450 
451  if (m_guiMessageQueue) // forward to GUI if any
452  {
454  m_guiMessageQueue->push(cfg);
455  }
456 }
457 
458 void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
459 {
460  qDebug() << "SSBDemod::applySettings:"
461  << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
462  << " m_rfBandwidth: " << settings.m_rfBandwidth
463  << " m_lowCutoff: " << settings.m_lowCutoff
464  << " m_volume: " << settings.m_volume
465  << " m_spanLog2: " << settings.m_spanLog2
466  << " m_audioBinaual: " << settings.m_audioBinaural
467  << " m_audioFlipChannels: " << settings.m_audioFlipChannels
468  << " m_dsb: " << settings.m_dsb
469  << " m_audioMute: " << settings.m_audioMute
470  << " m_agcActive: " << settings.m_agc
471  << " m_agcClamping: " << settings.m_agcClamping
472  << " m_agcTimeLog2: " << settings.m_agcTimeLog2
473  << " agcPowerThreshold: " << settings.m_agcPowerThreshold
474  << " agcThresholdGate: " << settings.m_agcThresholdGate
475  << " m_audioDeviceName: " << settings.m_audioDeviceName
476  << " m_useReverseAPI: " << settings.m_useReverseAPI
477  << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
478  << " m_reverseAPIPort: " << settings.m_reverseAPIPort
479  << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
480  << " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
481  << " force: " << force;
482 
483  QList<QString> reverseAPIKeys;
484 
485  if((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || force) {
486  reverseAPIKeys.append("inputFrequencyOffset");
487  }
488  if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) || force) {
489  reverseAPIKeys.append("rfBandwidth");
490  }
491  if((m_settings.m_lowCutoff != settings.m_lowCutoff) || force) {
492  reverseAPIKeys.append("lowCutoff");
493  }
494 
495  if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
496  (m_settings.m_lowCutoff != settings.m_lowCutoff) || force)
497  {
498  float band, lowCutoff;
499 
500  band = settings.m_rfBandwidth;
501  lowCutoff = settings.m_lowCutoff;
502 
503  if (band < 0) {
504  band = -band;
505  lowCutoff = -lowCutoff;
506  m_usb = false;
507  } else {
508  m_usb = true;
509  }
510 
511  if (band < 100.0f)
512  {
513  band = 100.0f;
514  lowCutoff = 0;
515  }
516 
517  m_Bandwidth = band;
518  m_LowCutoff = lowCutoff;
519 
520  m_settingsMutex.lock();
521  Real interpolatorBandwidth = (m_Bandwidth * 1.5f) > m_inputSampleRate ? m_inputSampleRate : (m_Bandwidth * 1.5f);
522  m_interpolator.create(16, m_inputSampleRate, interpolatorBandwidth, 2.0f);
525  SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate);
526  DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) m_audioSampleRate);
527  m_settingsMutex.unlock();
528  }
529 
530  if ((m_settings.m_volume != settings.m_volume) || force)
531  {
532  reverseAPIKeys.append("volume");
533  m_volume = settings.m_volume;
534  m_volume /= 4.0; // for 3276.8
535  }
536 
537  if ((m_settings.m_agcTimeLog2 != settings.m_agcTimeLog2) || force) {
538  reverseAPIKeys.append("agcTimeLog2");
539  }
540  if ((m_settings.m_agcPowerThreshold != settings.m_agcPowerThreshold) || force) {
541  reverseAPIKeys.append("agcPowerThreshold");
542  }
543  if ((m_settings.m_agcThresholdGate != settings.m_agcThresholdGate) || force) {
544  reverseAPIKeys.append("agcThresholdGate");
545  }
546  if ((m_settings.m_agcClamping != settings.m_agcClamping) || force) {
547  reverseAPIKeys.append("agcClamping");
548  }
549 
550  if ((m_settings.m_agcTimeLog2 != settings.m_agcTimeLog2) ||
553  (m_settings.m_agcClamping != settings.m_agcClamping) || force)
554  {
555  int agcNbSamples = (m_audioSampleRate / 1000) * (1<<settings.m_agcTimeLog2);
557  double agcPowerThreshold = CalcDb::powerFromdB(settings.m_agcPowerThreshold) * (SDR_RX_SCALED*SDR_RX_SCALED);
558  int agcThresholdGate = (m_audioSampleRate / 1000) * settings.m_agcThresholdGate; // ms
559  bool agcClamping = settings.m_agcClamping;
560 
561  if (m_agcNbSamples != agcNbSamples)
562  {
563  m_settingsMutex.lock();
564  m_agc.resize(agcNbSamples, agcNbSamples/2, agcTarget);
565  m_agc.setStepDownDelay(agcNbSamples);
566  m_agcNbSamples = agcNbSamples;
567  m_settingsMutex.unlock();
568  }
569 
570  if (m_agcPowerThreshold != agcPowerThreshold)
571  {
572  m_agc.setThreshold(agcPowerThreshold);
573  m_agcPowerThreshold = agcPowerThreshold;
574  }
575 
576  if (m_agcThresholdGate != agcThresholdGate)
577  {
578  m_agc.setGate(agcThresholdGate);
579  m_agcThresholdGate = agcThresholdGate;
580  }
581 
582  if (m_agcClamping != agcClamping)
583  {
584  m_agc.setClamping(agcClamping);
585  m_agcClamping = agcClamping;
586  }
587 
588  qDebug() << "SBDemod::applySettings: AGC:"
589  << " agcNbSamples: " << agcNbSamples
590  << " agcPowerThreshold: " << agcPowerThreshold
591  << " agcThresholdGate: " << agcThresholdGate
592  << " agcClamping: " << agcClamping;
593  }
594 
595  if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force)
596  {
597  reverseAPIKeys.append("audioDeviceName");
599  int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
600  audioDeviceManager->addAudioSink(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex);
601  uint32_t audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
602 
603  if (m_audioSampleRate != audioSampleRate) {
604  applyAudioSampleRate(audioSampleRate);
605  }
606  }
607 
608  if ((m_settings.m_spanLog2 != settings.m_spanLog2) || force) {
609  reverseAPIKeys.append("spanLog2");
610  }
611  if ((m_settings.m_audioBinaural != settings.m_audioBinaural) || force) {
612  reverseAPIKeys.append("audioBinaural");
613  }
614  if ((m_settings.m_audioFlipChannels != settings.m_audioFlipChannels) || force) {
615  reverseAPIKeys.append("audioFlipChannels");
616  }
617  if ((m_settings.m_dsb != settings.m_dsb) || force) {
618  reverseAPIKeys.append("dsb");
619  }
620  if ((m_settings.m_audioMute != settings.m_audioMute) || force) {
621  reverseAPIKeys.append("audioMute");
622  }
623  if ((m_settings.m_agc != settings.m_agc) || force) {
624  reverseAPIKeys.append("agc");
625  }
626 
627  m_spanLog2 = settings.m_spanLog2;
628  m_audioBinaual = settings.m_audioBinaural;
630  m_dsb = settings.m_dsb;
631  m_audioMute = settings.m_audioMute;
632  m_agcActive = settings.m_agc;
633 
634  if (settings.m_useReverseAPI)
635  {
636  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
641  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
642  }
643 
644  m_settings = settings;
645 }
646 
647 QByteArray SSBDemod::serialize() const
648 {
649  return m_settings.serialize();
650 }
651 
652 bool SSBDemod::deserialize(const QByteArray& data)
653 {
654  if (m_settings.deserialize(data))
655  {
658  return true;
659  }
660  else
661  {
665  return false;
666  }
667 }
668 
671  QString& errorMessage)
672 {
673  (void) errorMessage;
675  response.getSsbDemodSettings()->init();
677  return 200;
678 }
679 
681  bool force,
682  const QStringList& channelSettingsKeys,
684  QString& errorMessage)
685 {
686  (void) errorMessage;
687  SSBDemodSettings settings = m_settings;
688  bool frequencyOffsetChanged = false;
689 
690  if (channelSettingsKeys.contains("inputFrequencyOffset"))
691  {
693  frequencyOffsetChanged = true;
694  }
695  if (channelSettingsKeys.contains("rfBandwidth")) {
696  settings.m_rfBandwidth = response.getSsbDemodSettings()->getRfBandwidth();
697  }
698  if (channelSettingsKeys.contains("lowCutoff")) {
699  settings.m_lowCutoff = response.getSsbDemodSettings()->getLowCutoff();
700  }
701  if (channelSettingsKeys.contains("volume")) {
702  settings.m_volume = response.getSsbDemodSettings()->getVolume();
703  }
704  if (channelSettingsKeys.contains("spanLog2")) {
705  settings.m_spanLog2 = response.getSsbDemodSettings()->getSpanLog2();
706  }
707  if (channelSettingsKeys.contains("audioBinaural")) {
708  settings.m_audioBinaural = response.getSsbDemodSettings()->getAudioBinaural() != 0;
709  }
710  if (channelSettingsKeys.contains("audioFlipChannels")) {
711  settings.m_audioFlipChannels = response.getSsbDemodSettings()->getAudioFlipChannels() != 0;
712  }
713  if (channelSettingsKeys.contains("dsb")) {
714  settings.m_dsb = response.getSsbDemodSettings()->getDsb() != 0;
715  }
716  if (channelSettingsKeys.contains("audioMute")) {
717  settings.m_audioMute = response.getSsbDemodSettings()->getAudioMute() != 0;
718  }
719  if (channelSettingsKeys.contains("agc")) {
720  settings.m_agc = response.getSsbDemodSettings()->getAgc() != 0;
721  }
722  if (channelSettingsKeys.contains("agcClamping")) {
723  settings.m_agcClamping = response.getSsbDemodSettings()->getAgcClamping() != 0;
724  }
725  if (channelSettingsKeys.contains("agcTimeLog2")) {
726  settings.m_agcTimeLog2 = response.getSsbDemodSettings()->getAgcTimeLog2();
727  }
728  if (channelSettingsKeys.contains("agcPowerThreshold")) {
730  }
731  if (channelSettingsKeys.contains("agcThresholdGate")) {
733  }
734  if (channelSettingsKeys.contains("rgbColor")) {
735  settings.m_rgbColor = response.getSsbDemodSettings()->getRgbColor();
736  }
737  if (channelSettingsKeys.contains("title")) {
738  settings.m_title = *response.getSsbDemodSettings()->getTitle();
739  }
740  if (channelSettingsKeys.contains("audioDeviceName")) {
741  settings.m_audioDeviceName = *response.getSsbDemodSettings()->getAudioDeviceName();
742  }
743  if (channelSettingsKeys.contains("useReverseAPI")) {
744  settings.m_useReverseAPI = response.getSsbDemodSettings()->getUseReverseApi() != 0;
745  }
746  if (channelSettingsKeys.contains("reverseAPIAddress")) {
748  }
749  if (channelSettingsKeys.contains("reverseAPIPort")) {
750  settings.m_reverseAPIPort = response.getSsbDemodSettings()->getReverseApiPort();
751  }
752  if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
754  }
755  if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
757  }
758 
759  if (frequencyOffsetChanged)
760  {
763  m_inputMessageQueue.push(channelConfigMsg);
764  }
765 
766  MsgConfigureSSBDemod *msg = MsgConfigureSSBDemod::create(settings, force);
768 
769  qDebug("SSBDemod::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
770  if (m_guiMessageQueue) // forward to GUI if any
771  {
772  MsgConfigureSSBDemod *msgToGUI = MsgConfigureSSBDemod::create(settings, force);
773  m_guiMessageQueue->push(msgToGUI);
774  }
775 
776  webapiFormatChannelSettings(response, settings);
777 
778  return 200;
779 }
780 
783  QString& errorMessage)
784 {
785  (void) errorMessage;
787  response.getSsbDemodReport()->init();
788  webapiFormatChannelReport(response);
789  return 200;
790 }
791 
793 {
794  response.getSsbDemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
796  response.getSsbDemodSettings()->setRfBandwidth(settings.m_rfBandwidth);
797  response.getSsbDemodSettings()->setLowCutoff(settings.m_lowCutoff);
798  response.getSsbDemodSettings()->setVolume(settings.m_volume);
799  response.getSsbDemodSettings()->setSpanLog2(settings.m_spanLog2);
800  response.getSsbDemodSettings()->setAudioBinaural(settings.m_audioBinaural ? 1 : 0);
801  response.getSsbDemodSettings()->setAudioFlipChannels(settings.m_audioFlipChannels ? 1 : 0);
802  response.getSsbDemodSettings()->setDsb(settings.m_dsb ? 1 : 0);
803  response.getSsbDemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
804  response.getSsbDemodSettings()->setAgc(settings.m_agc ? 1 : 0);
805  response.getSsbDemodSettings()->setAgcClamping(settings.m_agcClamping ? 1 : 0);
806  response.getSsbDemodSettings()->setAgcTimeLog2(settings.m_agcTimeLog2);
809  response.getSsbDemodSettings()->setRgbColor(settings.m_rgbColor);
810 
811  if (response.getSsbDemodSettings()->getTitle()) {
812  *response.getSsbDemodSettings()->getTitle() = settings.m_title;
813  } else {
814  response.getSsbDemodSettings()->setTitle(new QString(settings.m_title));
815  }
816 
817  if (response.getSsbDemodSettings()->getAudioDeviceName()) {
818  *response.getSsbDemodSettings()->getAudioDeviceName() = settings.m_audioDeviceName;
819  } else {
820  response.getSsbDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
821  }
822 
823  response.getSsbDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
824 
825  if (response.getSsbDemodSettings()->getReverseApiAddress()) {
827  } else {
828  response.getSsbDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
829  }
830 
834 }
835 
837 {
838  double magsqAvg, magsqPeak;
839  int nbMagsqSamples;
840  getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
841 
842  response.getSsbDemodReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg));
843  response.getSsbDemodReport()->setSquelch(m_audioActive ? 1 : 0);
846 }
847 
848 void SSBDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBDemodSettings& settings, bool force)
849 {
851  swgChannelSettings->setDirection(0); // single sink (Rx)
852  swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
853  swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
854  swgChannelSettings->setChannelType(new QString("SSBDemod"));
855  swgChannelSettings->setSsbDemodSettings(new SWGSDRangel::SWGSSBDemodSettings());
856  SWGSDRangel::SWGSSBDemodSettings *swgSSBDemodSettings = swgChannelSettings->getSsbDemodSettings();
857 
858  // transfer data that has been modified. When force is on transfer all data except reverse API data
859 
860  if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
861  swgSSBDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
862  }
863  if (channelSettingsKeys.contains("rfBandwidth") || force) {
864  swgSSBDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
865  }
866  if (channelSettingsKeys.contains("lowCutoff") || force) {
867  swgSSBDemodSettings->setLowCutoff(settings.m_lowCutoff);
868  }
869  if (channelSettingsKeys.contains("volume") || force) {
870  swgSSBDemodSettings->setVolume(settings.m_volume);
871  }
872  if (channelSettingsKeys.contains("spanLog2") || force) {
873  swgSSBDemodSettings->setSpanLog2(settings.m_spanLog2);
874  }
875  if (channelSettingsKeys.contains("audioBinaural") || force) {
876  swgSSBDemodSettings->setAudioBinaural(settings.m_audioBinaural ? 1 : 0);
877  }
878  if (channelSettingsKeys.contains("audioFlipChannels") || force) {
879  swgSSBDemodSettings->setAudioFlipChannels(settings.m_audioFlipChannels ? 1 : 0);
880  }
881  if (channelSettingsKeys.contains("dsb") || force) {
882  swgSSBDemodSettings->setDsb(settings.m_dsb ? 1 : 0);
883  }
884  if (channelSettingsKeys.contains("audioMute") || force) {
885  swgSSBDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
886  }
887  if (channelSettingsKeys.contains("agc") || force) {
888  swgSSBDemodSettings->setAgc(settings.m_agc ? 1 : 0);
889  }
890  if (channelSettingsKeys.contains("agcClamping") || force) {
891  swgSSBDemodSettings->setAgcClamping(settings.m_agcClamping ? 1 : 0);
892  }
893  if (channelSettingsKeys.contains("agcTimeLog2") || force) {
894  swgSSBDemodSettings->setAgcTimeLog2(settings.m_agcTimeLog2);
895  }
896  if (channelSettingsKeys.contains("agcPowerThreshold") || force) {
897  swgSSBDemodSettings->setAgcPowerThreshold(settings.m_agcPowerThreshold);
898  }
899  if (channelSettingsKeys.contains("agcThresholdGate") || force) {
900  swgSSBDemodSettings->setAgcThresholdGate(settings.m_agcThresholdGate);
901  }
902  if (channelSettingsKeys.contains("rgbColor") || force) {
903  swgSSBDemodSettings->setRgbColor(settings.m_rgbColor);
904  }
905  if (channelSettingsKeys.contains("title") || force) {
906  swgSSBDemodSettings->setTitle(new QString(settings.m_title));
907  }
908  if (channelSettingsKeys.contains("audioDeviceName") || force) {
909  swgSSBDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
910  }
911 
912  QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
913  .arg(settings.m_reverseAPIAddress)
914  .arg(settings.m_reverseAPIPort)
915  .arg(settings.m_reverseAPIDeviceIndex)
916  .arg(settings.m_reverseAPIChannelIndex);
917  m_networkRequest.setUrl(QUrl(channelSettingsURL));
918  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
919 
920  QBuffer *buffer=new QBuffer();
921  buffer->open((QBuffer::ReadWrite));
922  buffer->write(swgChannelSettings->asJson().toUtf8());
923  buffer->seek(0);
924 
925  // Always use PATCH to avoid passing reverse API settings
926  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
927 
928  delete swgChannelSettings;
929 }
930 
931 void SSBDemod::networkManagerFinished(QNetworkReply *reply)
932 {
933  QNetworkReply::NetworkError replyError = reply->error();
934 
935  if (replyError)
936  {
937  qWarning() << "SSBDemod::networkManagerFinished:"
938  << " error(" << (int) replyError
939  << "): " << replyError
940  << ": " << reply->errorString();
941  return;
942  }
943 
944  QString answer = reply->readAll();
945  answer.chop(1); // remove last \n
946  qDebug("SSBDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
947 }
static MsgConfigureSSBDemodPrivate * create(Real Bandwidth, Real LowCutoff, Real volume, int spanLog2, bool audioBinaural, bool audioFlipChannels, bool dsb, bool audioMute, bool agc, bool agcClamping, int agcTimeLog2, int agcPowerThreshold, int agcThresholdGate)
Definition: ssbdemod.h:208
void webapiReverseSendSettings(QList< QString > &channelSettingsKeys, const SSBDemodSettings &settings, bool force)
Definition: ssbdemod.cpp:848
void setOriginatorChannelIndex(qint32 originator_channel_index)
void addAudioSink(AudioFifo *audioFifo, MessageQueue *sampleSinkMessageQueue, int outputDeviceIndex=-1)
Add the audio sink.
void setSsbDemodSettings(SWGSSBDemodSettings *ssb_demod_settings)
static const QString m_channelId
Definition: ssbdemod.h:177
int getOutputSampleRate(int outputDeviceIndex=-1)
void setInputFrequencyOffset(qint64 input_frequency_offset)
int m_agcThresholdGate
Gate length in number of samples befor threshold triggers.
Definition: ssbdemod.h:311
bool decimate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:38
SWGSSBDemodReport * getSsbDemodReport()
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
uint16_t m_reverseAPIPort
bool m_audioBinaual
Definition: ssbdemod.h:296
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void setAudioBinaural(qint32 audio_binaural)
void setSsbDemodReport(SWGSSBDemodReport *ssb_demod_report)
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force=false)
Definition: ssbdemod.cpp:385
void removeChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:163
fftfilt * SSBFilter
Definition: ssbdemod.h:319
void setThresholdEnable(bool enable)
Definition: agc.cpp:83
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
void addChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:156
bool m_dsb
Definition: ssbdemod.h:299
void setReverseApiChannelIndex(qint32 reverse_api_channel_index)
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport &response)
Definition: ssbdemod.cpp:836
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
double m_magsqPeak
Definition: ssbdemod.h:303
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
bool interpolate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:53
Real m_interpolatorDistance
Definition: ssbdemod.h:317
int getDeviceSetIndex() const
Definition: channelapi.h:89
void setAudioSampleRate(qint32 audio_sample_rate)
int getOutputDeviceIndex(const QString &deviceName) const
void setAgcClamping(qint32 agc_clamping)
void removeAudioSink(AudioFifo *audioFifo)
Remove the audio sink.
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
static const QString m_channelIdURI
Definition: ssbdemod.h:176
NCOF m_nco
Definition: ssbdemod.h:315
static MsgConfigureChannelizer * create(int sampleRate, int centerFrequency)
Definition: ssbdemod.h:81
Real m_Bandwidth
Definition: ssbdemod.h:288
static const int m_minPowerThresholdDB
double m_magsq
Definition: ssbdemod.h:301
QByteArray serialize() const
int m_magsqCount
Definition: ssbdemod.h:304
void getMagSqLevels(double &avg, double &peak, int &nbSamples)
Definition: ssbdemod.h:144
void setChannelType(QString *channel_type)
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)=0
void setOriginatorDeviceSetIndex(qint32 originator_device_set_index)
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
void setAudioDeviceName(QString *audio_device_name)
double feedAndGetValue(const Complex &ci)
Definition: agc.cpp:108
virtual int webapiSettingsGet(SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: ssbdemod.cpp:669
Real m_LowCutoff
Definition: ssbdemod.h:289
std::complex< float > cmplx
Definition: fftfilt.h:21
void write(const T &element)
Complex nextIQ()
Return next complex sample.
Definition: ncof.cpp:63
unsigned int uint32_t
Definition: rtptypes_win.h:46
bool deserialize(const QByteArray &data)
virtual int webapiSettingsPutPatch(bool force, const QStringList &channelSettingsKeys, SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: ssbdemod.cpp:680
void networkManagerFinished(QNetworkReply *reply)
Definition: ssbdemod.cpp:931
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings &response, const SSBDemodSettings &settings)
Definition: ssbdemod.cpp:792
QMutex m_settingsMutex
Definition: ssbdemod.h:333
BasebandSampleSink * m_sampleSink
Definition: ssbdemod.h:322
void applyAudioSampleRate(int sampleRate)
Definition: ssbdemod.cpp:411
void setAgcThresholdGate(qint32 agc_threshold_gate)
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
virtual bool handleMessage(const Message &cmd)=0
Processing of a message. Returns true if message has actually been processed.
void resize(int historySize, int stepLength, Real R)
Definition: agc.cpp:65
bool m_audioMute
Definition: ssbdemod.h:300
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
void create_filter(float f1, float f2)
Definition: fftfilt.cpp:107
int getSampleRate() const
Definition: dspcommands.h:390
static DSPEngine * instance()
Definition: dspengine.cpp:51
virtual void start()
Definition: ssbdemod.cpp:306
fftfilt * DSBFilter
Definition: ssbdemod.h:320
const SSBDemodSettings & getSettings() const
Definition: ssbdemod.h:55
fftfilt::cmplx m_sum
Definition: ssbdemod.h:292
SSBDemod(DeviceAPI *deviceAPI)
Definition: ssbdemod.cpp:51
void setClampMax(double clampMax)
Definition: agc.h:52
int32_t i
Definition: decimators.h:244
void setAgcPowerThreshold(qint32 agc_power_threshold)
#define agcTarget
Definition: freedvdemod.h:40
static bool match(const Message *message)
Definition: message.cpp:45
int m_undersampleCount
Definition: ssbdemod.h:293
bool m_agcClamping
Definition: ssbdemod.h:308
double m_magsqSum
Definition: ssbdemod.h:302
void setRfBandwidth(float rf_bandwidth)
void removeChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Remove a channel sink (Rx)
Definition: deviceapi.cpp:127
int m_agcNbSamples
number of audio (48 kHz) samples for AGC averaging
Definition: ssbdemod.h:309
int m_inputFrequencyOffset
Definition: ssbdemod.h:295
bool m_audioActive
True if an audio signal is produced (no AGC or AGC and above threshold)
Definition: ssbdemod.h:313
void setChannelSampleRate(qint32 channel_sample_rate)
int m_inputSampleRate
Definition: ssbdemod.h:294
DeviceAPI * m_deviceAPI
Definition: ssbdemod.h:283
bool m_usb
Definition: ssbdemod.h:298
DoubleBufferFIFO< fftfilt::cmplx > m_squelchDelayLine
Definition: ssbdemod.h:312
int m_spanLog2
Definition: ssbdemod.h:291
virtual QString asJson() override
uint16_t m_reverseAPIDeviceIndex
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)
Definition: ssbdemod.cpp:157
MagAGC m_agc
Definition: ssbdemod.h:306
virtual bool deserialize(const QByteArray &data)
Definition: ssbdemod.cpp:652
SSBDemodSettings m_settings
Definition: ssbdemod.h:286
AudioVector m_audioBuffer
Definition: ssbdemod.h:325
DownChannelizer * m_channelizer
Definition: ssbdemod.h:285
int getStepDownDelay() const
Definition: agc.h:53
T & readBack(int delay)
AudioDeviceManager * getAudioDeviceManager()
Definition: dspengine.h:55
virtual void stop()
Definition: ssbdemod.cpp:311
uint16_t m_reverseAPIChannelIndex
qint32 m_inputFrequencyOffset
void addChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Add a channel sink (Rx)
Definition: deviceapi.cpp:118
SWGSSBDemodSettings * getSsbDemodSettings()
virtual int webapiReportGet(SWGSDRangel::SWGChannelReport &response, QString &errorMessage)
Definition: ssbdemod.cpp:781
Real m_volume
Definition: ssbdemod.h:290
void setUseReverseApi(qint32 use_reverse_api)
bool setSize(uint32_t numSamples)
Definition: audiofifo.cpp:59
bool m_agcActive
Definition: ssbdemod.h:307
void applySettings(const SSBDemodSettings &settings, bool force=false)
Definition: ssbdemod.cpp:458
void setAudioFlipChannels(qint32 audio_flip_channels)
ThreadedBasebandSampleSink * m_threadedChannelizer
Definition: ssbdemod.h:284
int runSSB(const cmplx &in, cmplx **out, bool usb, bool getDC=true)
Definition: fftfilt.cpp:284
void setFreq(Real freq, Real sampleRate)
Definition: ncof.cpp:51
double m_agcPowerThreshold
AGC power threshold (linear)
Definition: ssbdemod.h:310
SampleVector m_sampleBuffer
Definition: ssbdemod.h:323
QString m_reverseAPIAddress
virtual ~SSBDemod()
Definition: ssbdemod.cpp:111
void setClamping(bool clamping)
Definition: agc.h:51
QNetworkAccessManager * m_networkManager
Definition: ssbdemod.h:330
void setThreshold(double threshold)
Definition: agc.h:47
AudioFifo m_audioFifo
Definition: ssbdemod.h:327
void setStepDownDelay(int stepDownDelay)
Definition: agc.h:50
bool m_audioFlipChannels
Definition: ssbdemod.h:297
void setAgcTimeLog2(qint32 agc_time_log2)
void setReverseApiAddress(QString *reverse_api_address)
void setGate(int gate)
Definition: agc.h:49
quint32 m_audioSampleRate
Definition: ssbdemod.h:328
void processOneSample(Complex &ci)
Definition: ssbdemod.cpp:189
static MsgConfigureSSBDemod * create(const SSBDemodSettings &settings, bool force)
Definition: ssbdemod.h:58
int getIndexInDeviceSet() const
Definition: channelapi.h:87
float getStepValue() const
Definition: agc.cpp:199
std::complex< Real > Complex
Definition: dsptypes.h:43
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
Definition: ssbdemod.cpp:315
uint m_audioBufferFill
Definition: ssbdemod.h:326
Real m_interpolatorDistanceRemain
Definition: ssbdemod.h:318
#define SDR_RX_SCALED
Definition: dsptypes.h:34
int runDSB(const cmplx &in, cmplx **out, bool getDC=true)
Definition: fftfilt.cpp:327
float Real
Definition: dsptypes.h:42
static double powerFromdB(double powerdB)
Definition: db.cpp:36
void setChannelPowerDb(float channel_power_db)
void setReverseApiPort(qint32 reverse_api_port)
uint32_t write(const quint8 *data, uint32_t numSamples)
Definition: audiofifo.cpp:66
void create_dsb_filter(float f2)
Definition: fftfilt.cpp:148
#define ssbFftLen
Definition: chanalyzer.h:38
Interpolator m_interpolator
Definition: ssbdemod.h:316
QNetworkRequest m_networkRequest
Definition: ssbdemod.h:331
void configure(MessageQueue *messageQueue, Real Bandwidth, Real LowCutoff, Real volume, int spanLog2, bool audioBinaural, bool audioFlipChannels, bool dsb, bool audioMute, bool agc, bool agcClamping, int agcTimeLog2, int agcPowerThreshold, int agcThresholdGate)
Definition: ssbdemod.cpp:125
virtual QByteArray serialize() const
Definition: ssbdemod.cpp:647