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.
airspyhfinput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2018 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 <string.h>
19 #include <errno.h>
20 
21 #include <QDebug>
22 #include <QNetworkReply>
23 #include <QBuffer>
24 
25 #include "SWGDeviceSettings.h"
26 #include "SWGDeviceState.h"
27 #include "SWGDeviceReport.h"
28 #include "SWGAirspyHFReport.h"
29 
30 #include "device/deviceapi.h"
31 #include "dsp/filerecord.h"
32 #include "dsp/dspcommands.h"
33 #include "dsp/dspengine.h"
34 
35 #include "airspyhfinput.h"
36 
37 #include "airspyhfplugin.h"
38 #include "airspyhfsettings.h"
39 #include "airspyhfthread.h"
40 
44 
45 const qint64 AirspyHFInput::loLowLimitFreqHF = 9000L;
46 const qint64 AirspyHFInput::loHighLimitFreqHF = 31000000L;
47 const qint64 AirspyHFInput::loLowLimitFreqVHF = 60000000L;
48 const qint64 AirspyHFInput::loHighLimitFreqVHF = 260000000L;
49 
51  m_deviceAPI(deviceAPI),
52  m_settings(),
53  m_dev(0),
54  m_airspyHFThread(0),
55  m_deviceDescription("AirspyHF"),
56  m_running(false)
57 {
58  openDevice();
59  m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
62  m_networkManager = new QNetworkAccessManager();
63  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
64 }
65 
67 {
68  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
69  delete m_networkManager;
70 
71  if (m_running) {
72  stop();
73  }
74 
76  delete m_fileSink;
77  closeDevice();
78 }
79 
81 {
82  delete this;
83 }
84 
86 {
87  if (m_dev != 0)
88  {
89  closeDevice();
90  }
91 
92  airspyhf_error rc;
93 
94  if (!m_sampleFifo.setSize(1<<19))
95  {
96  qCritical("AirspyHFInput::openDevice: could not allocate SampleFifo");
97  return false;
98  }
99 
101  {
102  qCritical("AirspyHFInput::openDevice: could not open Airspy HF with serial %s", qPrintable(m_deviceAPI->getSamplingDeviceSerial()));
103  m_dev = 0;
104  return false;
105  }
106  else
107  {
108  qDebug("AirspyHFInput::openDevice: opened Airspy HF with serial %s", qPrintable(m_deviceAPI->getSamplingDeviceSerial()));
109  }
110 
111  uint32_t nbSampleRates;
112  uint32_t *sampleRates;
113 
114  rc = (airspyhf_error) airspyhf_get_samplerates(m_dev, &nbSampleRates, 0);
115 
116  if (rc == AIRSPYHF_SUCCESS)
117  {
118  qDebug("AirspyHFInput::openDevice: %d sample rates for Airspy HF", nbSampleRates);
119  }
120  else
121  {
122  qCritical("AirspyHFInput::openDevice: could not obtain the number of Airspy HF sample rates");
123  closeDevice();
124  return false;
125  }
126 
127  sampleRates = new uint32_t[nbSampleRates];
128 
129  rc = (airspyhf_error) airspyhf_get_samplerates(m_dev, sampleRates, nbSampleRates);
130 
131  if (rc == AIRSPYHF_SUCCESS)
132  {
133  qDebug("AirspyHFInput::openDevice: obtained Airspy HF sample rates");
134  }
135  else
136  {
137  qCritical("AirspyHFInput::openDevice: could not obtain Airspy HF sample rates");
138  closeDevice();
139  return false;
140  }
141 
142  m_sampleRates.clear();
143 
144  for (unsigned int i = 0; i < nbSampleRates; i++)
145  {
146  m_sampleRates.push_back(sampleRates[i]);
147  qDebug("AirspyHFInput::openDevice: sampleRates[%d] = %u Hz", i, sampleRates[i]);
148  }
149 
150  delete[] sampleRates;
151 
152  return true;
153 }
154 
156 {
157  applySettings(m_settings, true);
158 }
159 
161 {
162  QMutexLocker mutexLocker(&m_mutex);
163 
164  if (!m_dev) {
165  return false;
166  }
167 
168  if (m_running) { stop(); }
169 
171  int sampleRateIndex = m_settings.m_devSampleRateIndex;
172 
174  sampleRateIndex = m_sampleRates.size() - 1;
175  }
176 
177  if (sampleRateIndex >= 0) {
178  m_airspyHFThread->setSamplerate(m_sampleRates[sampleRateIndex]);
179  }
180 
183 
184  mutexLocker.unlock();
185 
186  applySettings(m_settings, true);
187 
188  qDebug("AirspyHFInput::startInput: started");
189  m_running = true;
190 
191  return true;
192 }
193 
195 {
196  if (m_dev != 0)
197  {
198  airspyhf_stop(m_dev);
199  airspyhf_close(m_dev);
200  m_dev = 0;
201  }
202 
203  m_deviceDescription.clear();
204 }
205 
207 {
208  qDebug("AirspyHFInput::stop");
209  QMutexLocker mutexLocker(&m_mutex);
210 
211  if (m_airspyHFThread != 0)
212  {
214  delete m_airspyHFThread;
215  m_airspyHFThread = 0;
216  }
217 
218  m_running = false;
219 }
220 
221 QByteArray AirspyHFInput::serialize() const
222 {
223  return m_settings.serialize();
224 }
225 
226 bool AirspyHFInput::deserialize(const QByteArray& data)
227 {
228  bool success = true;
229 
230  if (!m_settings.deserialize(data))
231  {
233  success = false;
234  }
235 
237  m_inputMessageQueue.push(message);
238 
239  if (m_guiMessageQueue)
240  {
242  m_guiMessageQueue->push(messageToGUI);
243  }
244 
245  return success;
246 }
247 
249 {
250  return m_deviceDescription;
251 }
252 
254 {
255  int sampleRateIndex = m_settings.m_devSampleRateIndex;
256 
258  sampleRateIndex = m_sampleRates.size() - 1;
259  }
260 
261  if (sampleRateIndex >= 0)
262  {
263  int rate = m_sampleRates[sampleRateIndex];
264  return (rate / (1<<m_settings.m_log2Decim));
265  }
266  else
267  {
268  return 0;
269  }
270 }
271 
273 {
275 }
276 
277 void AirspyHFInput::setCenterFrequency(qint64 centerFrequency)
278 {
279  AirspyHFSettings settings = m_settings;
280  settings.m_centerFrequency = centerFrequency;
281 
282  MsgConfigureAirspyHF* message = MsgConfigureAirspyHF::create(settings, false);
283  m_inputMessageQueue.push(message);
284 
285  if (m_guiMessageQueue)
286  {
287  MsgConfigureAirspyHF* messageToGUI = MsgConfigureAirspyHF::create(settings, false);
288  m_guiMessageQueue->push(messageToGUI);
289  }
290 }
291 
293 {
294  if (MsgConfigureAirspyHF::match(message))
295  {
296  MsgConfigureAirspyHF& conf = (MsgConfigureAirspyHF&) message;
297  qDebug() << "MsgConfigureAirspyHF::handleMessage: MsgConfigureAirspyHF";
298 
299  bool success = applySettings(conf.getSettings(), conf.getForce());
300 
301  if (!success)
302  {
303  qDebug("MsgConfigureAirspyHF::handleMessage: AirspyHF config error");
304  }
305 
306  return true;
307  }
308  else if (MsgStartStop::match(message))
309  {
310  MsgStartStop& cmd = (MsgStartStop&) message;
311  qDebug() << "AirspyHFInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
312 
313  if (cmd.getStartStop())
314  {
316  {
318  }
319  }
320  else
321  {
323  }
324 
327  }
328 
329  return true;
330  }
331  else if (MsgFileRecord::match(message))
332  {
333  MsgFileRecord& conf = (MsgFileRecord&) message;
334  qDebug() << "AirspyHFInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
335 
336  if (conf.getStartStop())
337  {
338  if (m_settings.m_fileRecordName.size() != 0) {
340  } else {
342  }
343 
345  }
346  else
347  {
349  }
350 
351  return true;
352  }
353  else
354  {
355  return false;
356  }
357 }
358 
359 void AirspyHFInput::setDeviceCenterFrequency(quint64 freq_hz, const AirspyHFSettings& settings)
360 {
361  switch(settings.m_bandIndex)
362  {
363  case 1:
364  freq_hz = freq_hz < loLowLimitFreqVHF ? loLowLimitFreqVHF : freq_hz > loHighLimitFreqVHF ? loHighLimitFreqVHF : freq_hz;
365  break;
366  case 0:
367  default:
368  freq_hz = freq_hz < loLowLimitFreqHF ? loLowLimitFreqHF : freq_hz > loHighLimitFreqHF ? loHighLimitFreqHF : freq_hz;
369  break;
370  }
371 
372  airspyhf_error rc = (airspyhf_error) airspyhf_set_freq(m_dev, static_cast<uint32_t>(freq_hz));
373 
374  if (rc == AIRSPYHF_SUCCESS) {
375  qDebug("AirspyHFInput::setDeviceCenterFrequency: frequency set to %llu Hz", freq_hz);
376  } else {
377  qWarning("AirspyHFInput::setDeviceCenterFrequency: could not frequency to %llu Hz", freq_hz);
378  }
379 }
380 
381 bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force)
382 {
383  qDebug() << "AirspyHFInput::applySettings: "
384  << " m_centerFrequency: " << settings.m_centerFrequency
385  << " m_devSampleRateIndex: " << settings.m_devSampleRateIndex
386  << " m_log2Decim: " << settings.m_log2Decim
387  << " m_LOppmTenths: " << settings.m_LOppmTenths
388  << " m_bandIndex: " << settings.m_bandIndex
389  << " m_transverterDeltaFrequency: " << settings.m_transverterDeltaFrequency
390  << " m_transverterMode: " << settings.m_transverterMode
391  << " m_fileRecordName: " << settings.m_fileRecordName
392  << " m_useDSP: " << settings.m_useDSP
393  << " m_useAGC: " << settings.m_useAGC
394  << " m_agcHigh: " << settings.m_agcHigh
395  << " m_useLNA: " << settings.m_useLNA
396  << " m_attenuatorSteps: " << settings.m_attenuatorSteps
397  << " m_useReverseAPI: " << settings.m_useReverseAPI
398  << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
399  << " m_reverseAPIPort: " << settings.m_reverseAPIPort
400  << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
401  << " m_dcBlock: " << settings.m_dcBlock
402  << " m_iqCorrection: " << settings.m_iqCorrection;
403 
404  QMutexLocker mutexLocker(&m_mutex);
405 
406  bool forwardChange = false;
407  airspyhf_error rc;
408  QList<QString> reverseAPIKeys;
409 
410  int sampleRateIndex = settings.m_devSampleRateIndex;
411 
412  if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) {
413  reverseAPIKeys.append("dcBlock");
414  }
415  if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) {
416  reverseAPIKeys.append("iqCorrection");
417  }
418 
419  if ((m_settings.m_dcBlock != settings.m_dcBlock) ||
420  (m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
421  {
423  }
424 
425  if ((m_settings.m_bandIndex != settings.m_bandIndex) || force) {
426  reverseAPIKeys.append("bandIndex");
427  }
428 
429  if ((m_settings.m_devSampleRateIndex != settings.m_devSampleRateIndex) || force)
430  {
431  reverseAPIKeys.append("devSampleRateIndex");
432  forwardChange = true;
433 
434  if (settings.m_devSampleRateIndex >= m_sampleRates.size()) {
435  sampleRateIndex = m_sampleRates.size() - 1;
436  }
437 
438  if ((m_dev != 0) && (sampleRateIndex >= 0))
439  {
440  rc = (airspyhf_error) airspyhf_set_samplerate(m_dev, sampleRateIndex);
441 
442  if (rc != AIRSPYHF_SUCCESS)
443  {
444  qCritical("AirspyHFInput::applySettings: could not set sample rate index %u (%d S/s)", sampleRateIndex, m_sampleRates[sampleRateIndex]);
445  }
446  else if (m_airspyHFThread != 0)
447  {
448  qDebug("AirspyHFInput::applySettings: sample rate set to index: %u (%d S/s)", sampleRateIndex, m_sampleRates[sampleRateIndex]);
449  m_airspyHFThread->setSamplerate(m_sampleRates[sampleRateIndex]);
450  }
451  }
452  }
453 
454  if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
455  {
456  reverseAPIKeys.append("log2Decim");
457  forwardChange = true;
458 
459  if (m_airspyHFThread != 0)
460  {
462  qDebug() << "AirspyInput: set decimation to " << (1<<settings.m_log2Decim);
463  }
464  }
465 
466  if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force)
467  {
468  reverseAPIKeys.append("LOppmTenths");
469 
470  if (m_dev != 0)
471  {
472  rc = (airspyhf_error) airspyhf_set_calibration(m_dev, settings.m_LOppmTenths * 100);
473 
474  if (rc != AIRSPYHF_SUCCESS)
475  {
476  qCritical("AirspyHFInput::applySettings: could not set LO ppm correction to %f", settings.m_LOppmTenths / 10.0f);
477  }
478  else if (m_airspyHFThread != 0)
479  {
480  qDebug("AirspyHFInput::applySettings: LO ppm correction set to %f", settings.m_LOppmTenths / 10.0f);
481  }
482  }
483  }
484 
485  if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency)) {
486  reverseAPIKeys.append("centerFrequency");
487  }
488  if (force || (m_settings.m_transverterMode != settings.m_transverterMode)) {
489  reverseAPIKeys.append("transverterMode");
490  }
492  reverseAPIKeys.append("transverterDeltaFrequency");
493  }
494 
495  if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency)
498  {
499  qint64 deviceCenterFrequency = settings.m_centerFrequency;
500  deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0;
501  deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency;
502  qint64 f_img = deviceCenterFrequency;
503 
504  if ((m_dev != 0) && (sampleRateIndex >= 0))
505  {
506  quint32 devSampleRate = m_sampleRates[sampleRateIndex];
507  setDeviceCenterFrequency(deviceCenterFrequency, settings);
508 
509  qDebug() << "AirspyHFInput::applySettings: center freq: " << settings.m_centerFrequency << " Hz"
510  << " device center freq: " << deviceCenterFrequency << " Hz"
511  << " device sample rate: " << devSampleRate << "Hz"
512  << " Actual sample rate: " << devSampleRate/(1<<m_settings.m_log2Decim) << "Hz"
513  << " img: " << f_img << "Hz";
514  }
515 
516  forwardChange = true;
517  }
518 
519  if ((m_settings.m_useAGC != settings.m_useAGC) || force)
520  {
521  reverseAPIKeys.append("useAGC");
522 
523  if (m_dev != 0)
524  {
525  rc = (airspyhf_error) airspyhf_set_hf_agc(m_dev, settings.m_useAGC ? 1 : 0);
526 
527  if (rc != AIRSPYHF_SUCCESS) {
528  qCritical("AirspyHFInput::applySettings: could not set AGC to %d", settings.m_useAGC ? 1 : 0);
529  } else {
530  qDebug("AirspyHFInput::applySettings: set AGC to %d", settings.m_useAGC ? 1 : 0);
531  }
532  }
533  }
534 
535  if ((m_settings.m_agcHigh != settings.m_agcHigh) || force)
536  {
537  reverseAPIKeys.append("agcHigh");
538 
539  if (m_dev != 0)
540  {
541  rc = (airspyhf_error) airspyhf_set_hf_agc_threshold(m_dev, settings.m_agcHigh ? 1 : 0);
542 
543  if (rc != AIRSPYHF_SUCCESS) {
544  qCritical("AirspyHFInput::applySettings: could not set AGC to %s", settings.m_agcHigh ? "high" : "low");
545  } else {
546  qDebug("AirspyHFInput::applySettings: set AGC to %s", settings.m_agcHigh ? "high" : "low");
547  }
548  }
549  }
550 
551  if ((m_settings.m_useDSP != settings.m_useDSP) || force)
552  {
553  reverseAPIKeys.append("useDSP");
554 
555  if (m_dev != 0)
556  {
557  rc = (airspyhf_error) airspyhf_set_lib_dsp(m_dev, settings.m_useDSP ? 1 : 0);
558 
559  if (rc != AIRSPYHF_SUCCESS) {
560  qCritical("AirspyHFInput::applySettings: could not set DSP to %d", settings.m_useDSP ? 1 : 0);
561  } else {
562  qDebug("AirspyHFInput::applySettings: set DSP to %d", settings.m_useDSP ? 1 : 0);
563  }
564  }
565  }
566 
567  if ((m_settings.m_useLNA != settings.m_useLNA) || force)
568  {
569  reverseAPIKeys.append("useLNA");
570 
571  if (m_dev != 0)
572  {
573  rc = (airspyhf_error) airspyhf_set_hf_lna(m_dev, settings.m_useLNA ? 1 : 0);
574 
575  if (rc != AIRSPYHF_SUCCESS) {
576  qCritical("AirspyHFInput::applySettings: could not set LNA to %d", settings.m_useLNA ? 1 : 0);
577  } else {
578  qDebug("AirspyHFInput::applySettings: set LNA to %d", settings.m_useLNA ? 1 : 0);
579  }
580  }
581  }
582 
583  if ((m_settings.m_attenuatorSteps != settings.m_attenuatorSteps) || force)
584  {
585  reverseAPIKeys.append("attenuatorSteps");
586 
587  if (m_dev != 0)
588  {
589  rc = (airspyhf_error) airspyhf_set_hf_att(m_dev, settings.m_attenuatorSteps);
590 
591  if (rc != AIRSPYHF_SUCCESS) {
592  qCritical("AirspyHFInput::applySettings: could not set attenuator to %d dB", settings.m_attenuatorSteps * 6);
593  } else {
594  qDebug("AirspyHFInput::applySettings: set attenuator to %d dB", settings.m_attenuatorSteps * 6);
595  }
596  }
597  }
598 
599  if (forwardChange && (sampleRateIndex >= 0))
600  {
601  int sampleRate = m_sampleRates[sampleRateIndex]/(1<<settings.m_log2Decim);
602  DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, settings.m_centerFrequency);
603  m_fileSink->handleMessage(*notif); // forward to file sink
605  }
606 
607  if (settings.m_useReverseAPI)
608  {
609  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
613  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
614  }
615 
616  m_settings = settings;
617  return true;
618 }
619 
620 airspyhf_device_t *AirspyHFInput::open_airspyhf_from_serial(const QString& serialStr)
621 {
622  airspyhf_device_t *devinfo;
623  bool ok;
624  airspyhf_error rc;
625 
626  uint64_t serial = serialStr.toULongLong(&ok, 16);
627 
628  if (!ok)
629  {
630  qCritical("AirspyHFInput::open_airspyhf_from_serial: invalid serial %s", qPrintable(serialStr));
631  return 0;
632  }
633  else
634  {
635  rc = (airspyhf_error) airspyhf_open_sn(&devinfo, serial);
636 
637  if (rc == AIRSPYHF_SUCCESS) {
638  return devinfo;
639  } else {
640  return 0;
641  }
642  }
643 }
644 
647  QString& errorMessage)
648 {
649  (void) errorMessage;
651  response.getAirspyHfSettings()->init();
653  return 200;
654 }
655 
657  bool force,
658  const QStringList& deviceSettingsKeys,
659  SWGSDRangel::SWGDeviceSettings& response, // query + response
660  QString& errorMessage)
661 {
662  (void) errorMessage;
663  AirspyHFSettings settings = m_settings;
664 
665  if (deviceSettingsKeys.contains("centerFrequency")) {
667  }
668  if (deviceSettingsKeys.contains("devSampleRateIndex")) {
670  }
671  if (deviceSettingsKeys.contains("LOppmTenths")) {
672  settings.m_LOppmTenths = response.getAirspyHfSettings()->getLOppmTenths();
673  }
674  if (deviceSettingsKeys.contains("log2Decim")) {
675  settings.m_log2Decim = response.getAirspyHfSettings()->getLog2Decim();
676  }
677  if (deviceSettingsKeys.contains("transverterDeltaFrequency")) {
679  }
680  if (deviceSettingsKeys.contains("transverterMode")) {
681  settings.m_transverterMode = response.getAirspyHfSettings()->getTransverterMode() != 0;
682  }
683  if (deviceSettingsKeys.contains("bandIndex")) {
684  settings.m_bandIndex = response.getAirspyHfSettings()->getBandIndex();
685  }
686  if (deviceSettingsKeys.contains("fileRecordName")) {
687  settings.m_fileRecordName = *response.getAirspyHfSettings()->getFileRecordName();
688  }
689  if (deviceSettingsKeys.contains("useReverseAPI")) {
690  settings.m_useReverseAPI = response.getAirspyHfSettings()->getUseReverseApi() != 0;
691  }
692  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
694  }
695  if (deviceSettingsKeys.contains("reverseAPIPort")) {
696  settings.m_reverseAPIPort = response.getAirspyHfSettings()->getReverseApiPort();
697  }
698  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
700  }
701  if (deviceSettingsKeys.contains("useAGC")) {
702  settings.m_useAGC = response.getAirspyHfSettings()->getUseAgc();
703  }
704  if (deviceSettingsKeys.contains("agcHigh")) {
705  settings.m_agcHigh = response.getAirspyHfSettings()->getAgcHigh();
706  }
707  if (deviceSettingsKeys.contains("useDSP")) {
708  settings.m_useDSP = response.getAirspyHfSettings()->getUseDsp();
709  }
710  if (deviceSettingsKeys.contains("useLNA")) {
711  settings.m_useLNA = response.getAirspyHfSettings()->getUseLna();
712  }
713  if (deviceSettingsKeys.contains("attenuatorSteps")) {
715  }
716  if (deviceSettingsKeys.contains("dcBlock")) {
717  settings.m_dcBlock = response.getAirspyHfSettings()->getDcBlock() != 0;
718  }
719  if (deviceSettingsKeys.contains("iqCorrection")) {
720  settings.m_iqCorrection = response.getAirspyHfSettings()->getIqCorrection() != 0;
721  }
722 
723  MsgConfigureAirspyHF *msg = MsgConfigureAirspyHF::create(settings, force);
725 
726  if (m_guiMessageQueue) // forward to GUI if any
727  {
728  MsgConfigureAirspyHF *msgToGUI = MsgConfigureAirspyHF::create(settings, force);
729  m_guiMessageQueue->push(msgToGUI);
730  }
731 
732  webapiFormatDeviceSettings(response, settings);
733  return 200;
734 }
735 
737 {
740  response.getAirspyHfSettings()->setLOppmTenths(settings.m_LOppmTenths);
741  response.getAirspyHfSettings()->setLog2Decim(settings.m_log2Decim);
743  response.getAirspyHfSettings()->setTransverterMode(settings.m_transverterMode ? 1 : 0);
744  response.getAirspyHfSettings()->setBandIndex(settings.m_bandIndex ? 1 : 0);
745 
746  if (response.getAirspyHfSettings()->getFileRecordName()) {
747  *response.getAirspyHfSettings()->getFileRecordName() = settings.m_fileRecordName;
748  } else {
749  response.getAirspyHfSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
750  }
751 
752  response.getAirspyHfSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
753 
754  if (response.getAirspyHfSettings()->getReverseApiAddress()) {
756  } else {
757  response.getAirspyHfSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
758  }
759 
762  response.getAirspyHfSettings()->setUseAgc(settings.m_useAGC ? 1 : 0);
763  response.getAirspyHfSettings()->setUseDsp(settings.m_useDSP ? 1 : 0);
764  response.getAirspyHfSettings()->setUseLna(settings.m_useLNA ? 1 : 0);
765  response.getAirspyHfSettings()->setAgcHigh(settings.m_agcHigh ? 1 : 0);
767  response.getAirspyHfSettings()->setDcBlock(settings.m_dcBlock ? 1 : 0);
768  response.getAirspyHfSettings()->setIqCorrection(settings.m_iqCorrection ? 1 : 0);
769 }
770 
772 {
773  response.getAirspyHfReport()->setSampleRates(new QList<SWGSDRangel::SWGSampleRate*>);
774 
775  for (std::vector<uint32_t>::const_iterator it = getSampleRates().begin(); it != getSampleRates().end(); ++it)
776  {
778  response.getAirspyHfReport()->getSampleRates()->back()->setRate(*it);
779  }
780 }
781 
784  QString& errorMessage)
785 {
786  (void) errorMessage;
788  response.getAirspyHfReport()->init();
789  webapiFormatDeviceReport(response);
790  return 200;
791 }
792 
794  SWGSDRangel::SWGDeviceState& response,
795  QString& errorMessage)
796 {
797  (void) errorMessage;
799  return 200;
800 }
801 
803  bool run,
804  SWGSDRangel::SWGDeviceState& response,
805  QString& errorMessage)
806 {
807  (void) errorMessage;
809  MsgStartStop *message = MsgStartStop::create(run);
810  m_inputMessageQueue.push(message);
811 
812  if (m_guiMessageQueue) // forward to GUI if any
813  {
814  MsgStartStop *msgToGUI = MsgStartStop::create(run);
815  m_guiMessageQueue->push(msgToGUI);
816  }
817 
818  return 200;
819 }
820 
821 void AirspyHFInput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const AirspyHFSettings& settings, bool force)
822 {
824  swgDeviceSettings->setDirection(0); // single Rx
825  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
826  swgDeviceSettings->setDeviceHwType(new QString("AirspyHF"));
827  swgDeviceSettings->setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
828  SWGSDRangel::SWGAirspyHFSettings *swgAirspyHFSettings = swgDeviceSettings->getAirspyHfSettings();
829 
830  // transfer data that has been modified. When force is on transfer all data except reverse API data
831 
832  if (deviceSettingsKeys.contains("centerFrequency") || force) {
833  swgAirspyHFSettings->setCenterFrequency(settings.m_centerFrequency);
834  }
835  if (deviceSettingsKeys.contains("devSampleRateIndex") || force) {
836  swgAirspyHFSettings->setDevSampleRateIndex(settings.m_devSampleRateIndex);
837  }
838  if (deviceSettingsKeys.contains("LOppmTenths") || force) {
839  swgAirspyHFSettings->setLOppmTenths(settings.m_LOppmTenths);
840  }
841  if (deviceSettingsKeys.contains("log2Decim") || force) {
842  swgAirspyHFSettings->setLog2Decim(settings.m_log2Decim);
843  }
844  if (deviceSettingsKeys.contains("transverterDeltaFrequency") || force) {
845  swgAirspyHFSettings->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency);
846  }
847  if (deviceSettingsKeys.contains("transverterMode") || force) {
848  swgAirspyHFSettings->setTransverterMode(settings.m_transverterMode ? 1 : 0);
849  }
850  if (deviceSettingsKeys.contains("bandIndex") || force) {
851  swgAirspyHFSettings->setBandIndex(settings.m_bandIndex);
852  }
853  if (deviceSettingsKeys.contains("fileRecordName") || force) {
854  swgAirspyHFSettings->setFileRecordName(new QString(settings.m_fileRecordName));
855  }
856  if (deviceSettingsKeys.contains("useAGC")) {
857  swgAirspyHFSettings->setUseAgc(settings.m_useAGC ? 1 : 0);
858  }
859  if (deviceSettingsKeys.contains("agcHigh")) {
860  swgAirspyHFSettings->setAgcHigh(settings.m_agcHigh ? 1 : 0);
861  }
862  if (deviceSettingsKeys.contains("useDSP")) {
863  swgAirspyHFSettings->setUseDsp(settings.m_useDSP ? 1 : 0);
864  }
865  if (deviceSettingsKeys.contains("useLNA")) {
866  swgAirspyHFSettings->setUseLna(settings.m_useLNA ? 1 : 0);
867  }
868  if (deviceSettingsKeys.contains("attenuatorSteps")) {
869  swgAirspyHFSettings->setAttenuatorSteps(settings.m_attenuatorSteps);
870  }
871  if (deviceSettingsKeys.contains("dcBlock") || force) {
872  swgAirspyHFSettings->setDcBlock(settings.m_dcBlock ? 1 : 0);
873  }
874  if (deviceSettingsKeys.contains("iqCorrection") || force) {
875  swgAirspyHFSettings->setIqCorrection(settings.m_iqCorrection ? 1 : 0);
876  }
877 
878  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
879  .arg(settings.m_reverseAPIAddress)
880  .arg(settings.m_reverseAPIPort)
881  .arg(settings.m_reverseAPIDeviceIndex);
882  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
883  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
884 
885  QBuffer *buffer=new QBuffer();
886  buffer->open((QBuffer::ReadWrite));
887  buffer->write(swgDeviceSettings->asJson().toUtf8());
888  buffer->seek(0);
889 
890  // Always use PATCH to avoid passing reverse API settings
891  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
892 
893  delete swgDeviceSettings;
894 }
895 
897 {
899  swgDeviceSettings->setDirection(0); // single Rx
900  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
901  swgDeviceSettings->setDeviceHwType(new QString("AirspyHF"));
902 
903  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
907  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
908  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
909 
910  QBuffer *buffer=new QBuffer();
911  buffer->open((QBuffer::ReadWrite));
912  buffer->write(swgDeviceSettings->asJson().toUtf8());
913  buffer->seek(0);
914 
915  if (start) {
916  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
917  } else {
918  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
919  }
920 
921  delete swgDeviceSettings;
922 }
923 
924 void AirspyHFInput::networkManagerFinished(QNetworkReply *reply)
925 {
926  QNetworkReply::NetworkError replyError = reply->error();
927 
928  if (replyError)
929  {
930  qWarning() << "AirspyHFInput::networkManagerFinished:"
931  << " error(" << (int) replyError
932  << "): " << replyError
933  << ": " << reply->errorString();
934  return;
935  }
936 
937  QString answer = reply->readAll();
938  answer.chop(1); // remove last \n
939  qDebug("AirspyHFInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
940 }
static const qint64 loHighLimitFreqVHF
void setDeviceCenterFrequency(quint64 freq, const AirspyHFSettings &settings)
static MsgConfigureAirspyHF * create(const AirspyHFSettings &settings, bool force)
Definition: airspyhfinput.h:46
bool deserialize(const QByteArray &data)
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
static MsgStartStop * create(bool startStop)
Definition: airspyhfinput.h:87
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
virtual const QString & getDeviceDescription() const
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
Definition: deviceapi.cpp:266
static const qint64 loLowLimitFreqVHF
void setFileName(const QString &filename)
Definition: filerecord.cpp:59
uint getDeviceUID() const
Return the current device engine unique ID.
Definition: deviceapi.cpp:303
QString m_deviceDescription
void setNbSourceStreams(uint32_t nbSourceStreams)
Definition: deviceapi.h:168
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const AirspyHFSettings &settings, bool force)
airspyhf_device_t * m_dev
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
void setLog2Decimation(unsigned int log2_decim)
void startRecording()
Definition: filerecord.cpp:105
MessageQueue m_inputMessageQueue
Input queue to the source.
virtual QString asJson() override
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const AirspyHFSettings &settings)
airspyhf_device_t * open_airspyhf_from_serial(const QString &serialStr)
AirspyHFInput(DeviceAPI *deviceAPI)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
std::vector< uint32_t > m_sampleRates
virtual QByteArray serialize() const
void setUseReverseApi(qint32 use_reverse_api)
uint16_t m_reverseAPIDeviceIndex
AirspyHFThread * m_airspyHFThread
uint16_t m_reverseAPIPort
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
void setReverseApiAddress(QString *reverse_api_address)
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
void setTransverterDeltaFrequency(qint64 transverter_delta_frequency)
void networkManagerFinished(QNetworkReply *reply)
virtual ~AirspyHFInput()
void setSamplerate(uint32_t samplerate)
void setOriginatorIndex(qint32 originator_index)
virtual void setCenterFrequency(qint64 centerFrequency)
SampleSinkFifo m_sampleFifo
bool setSize(int size)
unsigned int uint32_t
Definition: rtptypes_win.h:46
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
virtual bool handleMessage(const Message &message)
Processing of a message. Returns true if message has actually been processed.
Definition: filerecord.cpp:128
AirspyHFSettings m_settings
void setDevSampleRateIndex(qint32 dev_sample_rate_index)
int getDeviceSetIndex() const
Definition: deviceapi.h:131
DeviceAPI * m_deviceAPI
QNetworkRequest m_networkRequest
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
QList< SWGSampleRate * > * getSampleRates()
void addAncillarySink(BasebandSampleSink *sink, unsigned int index=0)
Adds a sink to receive full baseband and that is not a channel (e.g. spectrum)
Definition: deviceapi.cpp:89
void genUniqueFileName(uint deviceUID, int istream=-1)
Definition: filerecord.cpp:67
virtual bool deserialize(const QByteArray &data)
FileRecord * m_fileSink
File sink to record device I/Q output.
bool applySettings(const AirspyHFSettings &settings, bool force)
qint64 m_transverterDeltaFrequency
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
void stopRecording()
Definition: filerecord.cpp:117
int32_t i
Definition: decimators.h:244
void webapiReverseSendStartStop(bool start)
static bool match(const Message *message)
Definition: message.cpp:45
QString m_reverseAPIAddress
virtual int getSampleRate() const
Sample rate exposed by the source.
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
static const qint64 loLowLimitFreqHF
void setLOppmTenths(qint32 l_oppm_tenths)
void removeAncillarySink(BasebandSampleSink *sink, unsigned int index=0)
Removes it.
Definition: deviceapi.cpp:100
quint32 m_devSampleRateIndex
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
const std::vector< uint32_t > & getSampleRates() const
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
void setIqCorrection(qint32 iq_correction)
virtual bool start()
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
static const qint64 loHighLimitFreqHF
SWGAirspyHFSettings * getAirspyHfSettings()
const QString & getSamplingDeviceSerial() const
Definition: deviceapi.h:121
void setSampleRates(QList< SWGSampleRate *> *sample_rates)
void setReverseApiPort(qint32 reverse_api_port)
void setAirspyHfReport(SWGAirspyHFReport *airspy_hf_report)
virtual quint64 getCenterFrequency() const
Center frequency exposed by the source.
void setCenterFrequency(qint64 center_frequency)
void setFileRecordName(QString *file_record_name)
QNetworkAccessManager * m_networkManager
QByteArray serialize() const
virtual void stop()
void setAirspyHfSettings(SWGAirspyHFSettings *airspy_hf_settings)
void setTransverterMode(qint32 transverter_mode)
const AirspyHFSettings & getSettings() const
Definition: airspyhfinput.h:43
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int streamIndex=0)
Configure current device engine DSP corrections (Rx)
Definition: deviceapi.cpp:355
void setDirection(qint32 direction)
virtual void destroy()
void setAttenuatorSteps(qint32 attenuator_steps)
void setDeviceHwType(QString *device_hw_type)
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
SWGAirspyHFReport * getAirspyHfReport()
virtual bool handleMessage(const Message &message)
unsigned __int64 uint64_t
Definition: rtptypes_win.h:48