diff --git a/Readme.md b/Readme.md index 47b980835..5277342d5 100644 --- a/Readme.md +++ b/Readme.md @@ -51,7 +51,7 @@ If you use your own location for libairspy install directory you need to specify `-DLIBAIRSPY_LIBRARIES=/opt/install/libairspy/lib/libairspy.so -DLIBAIRSPY_INCLUDE_DIR=/opt/install/libairspy/include` -Please note that if you are not using a recent version of libairspy (>= 1.0.6) the dynamic retrieval of sample rates is not supported. In this case you should modify the `plugins/samplesource/airspy/CMakeLists.txt` and change line `add_definitions(${QT_DEFINITIONS})` by `add_definitions("${QT_DEFINITIONS} -DLIBAIRSPY_OLD")`. In fact both lines are present with the former one commented out. +Please note that if you are using a recent version of libairspy (>= 1.0.6) the dynamic retrieval of sample rates is supported. To benefit from it you should modify the `plugins/samplesource/airspy/CMakeLists.txt` and change line `add_definitions(${QT_DEFINITIONS})` by `add_definitions("${QT_DEFINITIONS} -DLIBAIRSPY_DYN_RATES")`. In fact both lines are present with the last one commented out.

BladeRF

diff --git a/plugins/samplesource/airspy/CMakeLists.txt b/plugins/samplesource/airspy/CMakeLists.txt index bf39ea115..5eaeaa731 100644 --- a/plugins/samplesource/airspy/CMakeLists.txt +++ b/plugins/samplesource/airspy/CMakeLists.txt @@ -29,8 +29,8 @@ include_directories( ) #include(${QT_USE_FILE}) -#add_definitions("${QT_DEFINITIONS} -DLIBAIRSPY_OLD") -add_definitions(${QT_DEFINITIONS}) +#add_definitions(${QT_DEFINITIONS}) +add_definitions("${QT_DEFINITIONS} -DLIBAIRSPY_DYN_RATES") add_definitions(-DQT_PLUGIN) add_definitions(-DQT_SHARED) diff --git a/plugins/samplesource/airspy/airspygui.cpp b/plugins/samplesource/airspy/airspygui.cpp index 2cf2e838d..bf7189371 100644 --- a/plugins/samplesource/airspy/airspygui.cpp +++ b/plugins/samplesource/airspy/airspygui.cpp @@ -37,6 +37,9 @@ AirspyGui::AirspyGui(PluginAPI* pluginAPI, QWidget* parent) : displaySettings(); m_sampleSource = new AirspyInput(); + m_rates = ((AirspyInput*) m_sampleSource)->getSampleRates(); + displaySampleRates(); + connect(m_sampleSource->getOutputMessageQueueToGUI(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); DSPEngine::instance()->setSource(m_sampleSource); } @@ -94,7 +97,9 @@ bool AirspyGui::handleMessage(const Message& message) { if (AirspyInput::MsgReportAirspy::match(message)) { - displaySettings(); + qDebug() << "AirspyGui::handleMessage: MsgReportAirspy"; + m_rates = ((AirspyInput::MsgReportAirspy&) message).getSampleRates(); + displaySampleRates(); return true; } else @@ -103,6 +108,21 @@ bool AirspyGui::handleMessage(const Message& message) } } +void AirspyGui::handleSourceMessages() +{ + Message* message; + + while ((message = m_sampleSource->getOutputMessageQueueToGUI()->pop()) != 0) + { + qDebug("AirspyGui::HandleSourceMessages: message: %s", message->getIdentifier()); + + if (handleMessage(*message)) + { + delete message; + } + } +} + void AirspyGui::displaySettings() { ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); @@ -129,6 +149,33 @@ void AirspyGui::displaySettings() ui->vga->setValue(m_settings.m_vgaGain); } +void AirspyGui::displaySampleRates() +{ + int savedIndex = m_settings.m_devSampleRateIndex; + ui->sampleRate->blockSignals(true); + + if (m_rates.size() > 0) + { + ui->sampleRate->clear(); + + for (int i = 0; i < m_rates.size(); i++) + { + ui->sampleRate->addItem(QString("%1M").arg(QString::number(m_rates[i]/1000000.0, 'f', 3))); + } + } + + ui->sampleRate->blockSignals(false); + + if (savedIndex < m_rates.size()) + { + ui->sampleRate->setCurrentIndex(savedIndex); + } + else + { + ui->sampleRate->setCurrentIndex((int) m_rates.size()-1); + } +} + void AirspyGui::sendSettings() { if(!m_updateTimer.isActive()) @@ -188,7 +235,7 @@ void AirspyGui::on_lna_valueChanged(int value) if ((value < 0) || (value > 14)) return; - ui->lnaGainText->setText(tr("%1dB").arg(value*3)); + ui->lnaGainText->setText(tr("%1dB").arg(value)); m_settings.m_lnaGain = value; sendSettings(); } @@ -198,7 +245,7 @@ void AirspyGui::on_mix_valueChanged(int value) if ((value < 0) || (value > 15)) return; - ui->mixText->setText(tr("%1dB").arg(value*3)); + ui->mixText->setText(tr("%1dB").arg(value)); m_settings.m_lnaGain = value; sendSettings(); } @@ -208,7 +255,7 @@ void AirspyGui::on_vga_valueChanged(int value) if ((value < 0) || (value > 15)) return; - ui->vgaText->setText(tr("%1dB").arg(value*3)); + ui->vgaText->setText(tr("%1dB").arg(value)); m_settings.m_lnaGain = value; sendSettings(); } diff --git a/plugins/samplesource/airspy/airspygui.h b/plugins/samplesource/airspy/airspygui.h index 377d2d608..a65f3c9a9 100644 --- a/plugins/samplesource/airspy/airspygui.h +++ b/plugins/samplesource/airspy/airspygui.h @@ -60,6 +60,7 @@ private: SampleSource* m_sampleSource; void displaySettings(); + void displaySampleRates(); void sendSettings(); private slots: @@ -73,6 +74,7 @@ private slots: void on_mix_valueChanged(int value); void on_vga_valueChanged(int value); void updateHardware(); + void handleSourceMessages(); }; #endif // INCLUDE_AIRSPYGUI_H diff --git a/plugins/samplesource/airspy/airspygui.ui b/plugins/samplesource/airspy/airspygui.ui index 72e00564b..8a9071808 100644 --- a/plugins/samplesource/airspy/airspygui.ui +++ b/plugins/samplesource/airspy/airspygui.ui @@ -351,7 +351,7 @@ 1 - 15 + 5 Qt::Horizontal @@ -410,7 +410,7 @@ 1 - 9 + 5 Qt::Horizontal diff --git a/plugins/samplesource/airspy/airspyinput.cpp b/plugins/samplesource/airspy/airspyinput.cpp index 79b318473..541e8fec7 100644 --- a/plugins/samplesource/airspy/airspyinput.cpp +++ b/plugins/samplesource/airspy/airspyinput.cpp @@ -100,6 +100,8 @@ AirspyInput::AirspyInput() : m_airspyThread(0), m_deviceDescription("Airspy") { + m_sampleRates.push_back(10000000); + m_sampleRates.push_back(2500000); } AirspyInput::~AirspyInput() @@ -135,16 +137,13 @@ bool AirspyInput::start(int device) return false; } - if ((m_dev = open_airspy_from_sequence(device)) == 0) // TODO: fix; Open first available device as there is no proper handling for multiple devices + if ((m_dev = open_airspy_from_sequence(device)) == 0) { - qCritical("AirspyInput::start: could not open Airspy"); + qCritical("AirspyInput::start: could not open Airspy #%d", device); return false; } -#ifdef LIBAIRSPY_OLD - m_sampleRates.push_back(2500000); - m_sampleRates.push_back(10000000); -#else +#ifdef LIBAIRSPY_DYN_RATES uint32_t nbSampleRates; uint32_t *sampleRates; @@ -160,14 +159,20 @@ bool AirspyInput::start(int device) return false; } + m_sampleRates.clear(); + for (int i=0; ipush(message); + rc = (airspy_error) airspy_set_sample_type(m_dev, AIRSPY_SAMPLE_INT16_IQ); if (rc != AIRSPY_SUCCESS) @@ -176,31 +181,27 @@ bool AirspyInput::start(int device) return false; } - applySettings(m_settings, true); - - MsgReportAirspy *message = MsgReportAirspy::create(m_sampleRates); - getOutputMessageQueueToGUI()->push(message); - - if((m_airspyThread = new AirspyThread(m_dev, &m_sampleFifo)) == NULL) { - qFatal("out of memory"); - goto failed; + if((m_airspyThread = new AirspyThread(m_dev, &m_sampleFifo)) == 0) + { + qFatal("AirspyInput::start: out of memory"); + stop(); + return false; } m_airspyThread->startWork(); mutexLocker.unlock(); + applySettings(m_settings, true); + qDebug("AirspyInput::startInput: started"); return true; - -failed: - stop(); - return false; } void AirspyInput::stop() { + qDebug("AirspyInput::stop"); QMutexLocker mutexLocker(&m_mutex); if(m_airspyThread != 0) @@ -243,7 +244,9 @@ bool AirspyInput::handleMessage(const Message& message) MsgConfigureAirspy& conf = (MsgConfigureAirspy&) message; qDebug() << "AirspyInput::handleMessage: MsgConfigureAirspy"; - if (!applySettings(conf.getSettings(), false)) + bool success = applySettings(conf.getSettings(), false); + + if (!success) { qDebug("Airspy config error"); } @@ -274,32 +277,29 @@ void AirspyInput::setCenterFrequency(quint64 freq_hz) bool AirspyInput::applySettings(const Settings& settings, bool force) { - bool forwardChange = false; - airspy_error rc; - qint64 deviceCenterFrequency = m_settings.m_centerFrequency; - qint64 f_img = deviceCenterFrequency; - quint32 devSampleRate = m_sampleRates[m_settings.m_devSampleRateIndex]; - QMutexLocker mutexLocker(&m_mutex); - qDebug() << "AirspyInput::applySettings: m_dev: " << m_dev; + bool forwardChange = false; + airspy_error rc; + + qDebug() << "AirspyInput::applySettings"; if ((m_settings.m_devSampleRateIndex != settings.m_devSampleRateIndex) || force) { + forwardChange = true; + if (settings.m_devSampleRateIndex < m_sampleRates.size()) { m_settings.m_devSampleRateIndex = settings.m_devSampleRateIndex; } else { - m_settings.m_devSampleRateIndex = m_sampleRates.size() - 1; + m_settings.m_devSampleRateIndex = m_sampleRates.size() - 1; } - forwardChange = true; - if (m_dev != 0) { - rc = (airspy_error) airspy_set_samplerate(m_dev, static_cast(m_sampleRates[m_settings.m_devSampleRateIndex])); + rc = (airspy_error) airspy_set_samplerate(m_dev, static_cast(m_settings.m_devSampleRateIndex)); if (rc != AIRSPY_SUCCESS) { @@ -336,6 +336,10 @@ bool AirspyInput::applySettings(const Settings& settings, bool force) } } + qint64 deviceCenterFrequency = m_settings.m_centerFrequency; + qint64 f_img = deviceCenterFrequency; + quint32 devSampleRate = m_sampleRates[m_settings.m_devSampleRateIndex]; + if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) { m_settings.m_centerFrequency = settings.m_centerFrequency; @@ -461,12 +465,16 @@ bool AirspyInput::applySettings(const Settings& settings, bool force) struct airspy_device *AirspyInput::open_airspy_from_sequence(int sequence) { - struct airspy_device *devinfo; - int rc; + airspy_read_partid_serialno_t read_partid_serialno; + struct airspy_device *devinfo, *retdev = 0; + uint32_t serial_msb = 0; + uint32_t serial_lsb = 0; + airspy_error rc; + int i; - for (int i=0; i < AIRSPY_MAX_DEVICE; i++) + for (int i = 0; i < AIRSPY_MAX_DEVICE; i++) { - rc = airspy_open(&devinfo); + rc = (airspy_error) airspy_open(&devinfo); if (rc == AIRSPY_SUCCESS) { @@ -474,10 +482,14 @@ struct airspy_device *AirspyInput::open_airspy_from_sequence(int sequence) { return devinfo; } + else + { + airspy_close(devinfo); + } } else { - break; // finished + break; } } diff --git a/plugins/samplesource/airspy/airspyinput.h b/plugins/samplesource/airspy/airspyinput.h index 863f28ebd..aa2639efd 100644 --- a/plugins/samplesource/airspy/airspyinput.h +++ b/plugins/samplesource/airspy/airspyinput.h @@ -98,6 +98,7 @@ public: virtual const QString& getDeviceDescription() const; virtual int getSampleRate() const; virtual quint64 getCenterFrequency() const; + const std::vector& getSampleRates() const { return m_sampleRates; } virtual bool handleMessage(const Message& message); diff --git a/plugins/samplesource/airspy/airspyplugin.cpp b/plugins/samplesource/airspy/airspyplugin.cpp index b0394e4c2..5651ffef8 100644 --- a/plugins/samplesource/airspy/airspyplugin.cpp +++ b/plugins/samplesource/airspy/airspyplugin.cpp @@ -53,8 +53,11 @@ PluginInterface::SampleSourceDevices AirspyPlugin::enumSampleSources() { SampleSourceDevices result; airspy_read_partid_serialno_t read_partid_serialno; - struct airspy_device *devinfo = 0; + struct airspy_device *devinfo; + uint32_t serial_msb = 0; + uint32_t serial_lsb = 0; airspy_error rc; + int i; rc = (airspy_error) airspy_init(); @@ -63,29 +66,40 @@ PluginInterface::SampleSourceDevices AirspyPlugin::enumSampleSources() qCritical("AirspyPlugin::enumSampleSources: failed to initiate Airspy library: %s", airspy_error_name(rc)); } - for (int i=0; i < AIRSPY_MAX_DEVICE; i++) + for (i=0; i < AIRSPY_MAX_DEVICE; i++) { rc = (airspy_error) airspy_open(&devinfo); if (rc == AIRSPY_SUCCESS) { + qDebug("AirspyPlugin::enumSampleSources: try to enumerate Airspy device #%d", i); + rc = (airspy_error) airspy_board_partid_serialno_read(devinfo, &read_partid_serialno); if (rc != AIRSPY_SUCCESS) { qDebug("AirspyPlugin::enumSampleSources: failed to read serial no: %s", airspy_error_name(rc)); + airspy_close(devinfo); continue; // next } - QString serial_str = QString::number(read_partid_serialno.serial_no[2], 16) + QString::number(read_partid_serialno.serial_no[3], 16); - uint64_t serial_num = (((uint64_t) read_partid_serialno.serial_no[2])<<32) + read_partid_serialno.serial_no[3]; - QString displayedName(QString("Airspy #%1 0x%2").arg(i+1).arg(serial_str)); - SimpleSerializer s(1); - s.writeS32(1, i); - s.writeString(2, serial_str); - s.writeU64(3, serial_num); + if ((read_partid_serialno.serial_no[2] != serial_msb) && (read_partid_serialno.serial_no[3] != serial_lsb)) + { + serial_msb = read_partid_serialno.serial_no[2]; + serial_lsb = read_partid_serialno.serial_no[3]; - result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.airspy", s.final())); + QString serial_str = QString::number(serial_msb, 16) + QString::number(serial_lsb, 16); + uint64_t serial_num = (((uint64_t) serial_msb)<<32) + serial_lsb; + QString displayedName(QString("Airspy #%1 0x%2").arg(i).arg(serial_str)); + SimpleSerializer s(1); + s.writeS32(1, i); + s.writeString(2, serial_str); + s.writeU64(3, serial_num); + result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.airspy", s.final())); + qDebug("AirspyPlugin::enumSampleSources: enumerated Airspy device #%d", i); + } + + airspy_close(devinfo); } else { @@ -94,7 +108,8 @@ PluginInterface::SampleSourceDevices AirspyPlugin::enumSampleSources() } } - airspy_exit(); + rc = (airspy_error) airspy_exit(); + qDebug("AirspyPlugin::enumSampleSources: airspy_exit: %s", airspy_error_name(rc)); return result; } diff --git a/plugins/samplesource/airspy/airspythread.cpp b/plugins/samplesource/airspy/airspythread.cpp index e837cce88..c01035ecf 100644 --- a/plugins/samplesource/airspy/airspythread.cpp +++ b/plugins/samplesource/airspy/airspythread.cpp @@ -52,6 +52,7 @@ void AirspyThread::startWork() void AirspyThread::stopWork() { + qDebug("AirspyThread::stopWork"); m_running = false; wait(); } @@ -92,6 +93,17 @@ void AirspyThread::run() } } + rc = (airspy_error) airspy_stop_rx(m_dev); + + if (rc == AIRSPY_SUCCESS) + { + qDebug("AirspyInput::run: stopped Airspy Rx"); + } + else + { + qDebug("AirspyInput::run: failed to stop Airspy Rx: %s", airspy_error_name(rc)); + } + m_running = false; } @@ -177,13 +189,13 @@ void AirspyThread::callback(const qint16* buf, qint32 len) } } - m_sampleFifo->write(m_convertBuffer.begin(), it); } int AirspyThread::rx_callback(airspy_transfer_t* transfer) { - qint32 bytes_to_write = transfer->sample_count * sizeof(qint16) * 2; + qint32 bytes_to_write = transfer->sample_count * sizeof(qint16); m_this->callback((qint16 *) transfer->samples, bytes_to_write); + return 0; } diff --git a/plugins/samplesource/airspy/airspythread.h b/plugins/samplesource/airspy/airspythread.h index 1e9a7b880..29097bf39 100644 --- a/plugins/samplesource/airspy/airspythread.h +++ b/plugins/samplesource/airspy/airspythread.h @@ -24,7 +24,7 @@ #include "dsp/samplefifo.h" #include "dsp/decimators.h" -#define AIRSPY_BLOCKSIZE (1<<14) +#define AIRSPY_BLOCKSIZE (1<<17) class AirspyThread : public QThread { Q_OBJECT