From b20feec1fd2c40db0b7f4f3d81c14d811c6a7d5a Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 25 Sep 2018 00:38:38 +0200 Subject: [PATCH] BladerRF2 input support (7). GUI and Plugin --- devices/bladerf2/devicebladerf2.cpp | 9 + .../bladerf1input/bladerf1inputgui.cpp | 6 +- .../samplesource/bladerf2input/CMakeLists.txt | 8 +- .../bladerf2input/bladerf2input.cpp | 30 +- .../bladerf2input/bladerf2input.h | 5 + .../bladerf2input/bladerf2inputgui.cpp | 333 +++++++++++++++ .../bladerf2input/bladerf2inputgui.h | 93 +++++ .../bladerf2input/bladerf2inputgui.ui | 382 +++++------------- .../bladerf2input/bladerf2inputplugin.cpp | 6 +- udev-rules/88-nuand.rules | 3 + 10 files changed, 573 insertions(+), 302 deletions(-) create mode 100644 plugins/samplesource/bladerf2input/bladerf2inputgui.cpp create mode 100644 plugins/samplesource/bladerf2input/bladerf2inputgui.h diff --git a/devices/bladerf2/devicebladerf2.cpp b/devices/bladerf2/devicebladerf2.cpp index 7b7e4a772..63d7c4c8c 100644 --- a/devices/bladerf2/devicebladerf2.cpp +++ b/devices/bladerf2/devicebladerf2.cpp @@ -79,6 +79,15 @@ bool DeviceBladeRF2::open(const char *serial) return true; } +void DeviceBladeRF2::close() +{ + if (m_dev) + { + bladerf_close(m_dev); + m_dev = 0; + } +} + struct bladerf *DeviceBladeRF2::open_bladerf_from_serial(const char *serial) { int status; diff --git a/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp b/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp index 220b3d33c..3865fedce 100644 --- a/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp +++ b/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp @@ -14,8 +14,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "bladerf1inputgui.h" - #include #include @@ -26,9 +24,11 @@ #include "gui/glspectrum.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" -#include +#include "device/devicesourceapi.h" #include "device/deviceuiset.h" +#include "bladerf1inputgui.h" + Bladerf1InputGui::Bladerf1InputGui(DeviceUISet *deviceUISet, QWidget* parent) : QWidget(parent), ui(new Ui::Bladerf1InputGui), diff --git a/plugins/samplesource/bladerf2input/CMakeLists.txt b/plugins/samplesource/bladerf2input/CMakeLists.txt index 6594e1cff..75d330454 100644 --- a/plugins/samplesource/bladerf2input/CMakeLists.txt +++ b/plugins/samplesource/bladerf2input/CMakeLists.txt @@ -3,17 +3,17 @@ project(bladerf2input) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(bladerf2input_SOURCES - #bladerf2inputgui.cpp + bladerf2inputgui.cpp bladerf2input.cpp - #bladerf2inputplugin.cpp + bladerf2inputplugin.cpp bladerf2inputsettings.cpp bladerf2inputthread.cpp ) set(bladerf2input_HEADERS - #bladerf2inputgui.h + bladerf2inputgui.h bladerf2input.h - #bladerf2inputplugin.h + bladerf2inputplugin.h bladerf2inputsettings.h bladerf2inputthread.h ) diff --git a/plugins/samplesource/bladerf2input/bladerf2input.cpp b/plugins/samplesource/bladerf2input/bladerf2input.cpp index 1b9709471..296fe3e44 100644 --- a/plugins/samplesource/bladerf2input/bladerf2input.cpp +++ b/plugins/samplesource/bladerf2input/bladerf2input.cpp @@ -417,6 +417,34 @@ void BladeRF2Input::setCenterFrequency(qint64 centerFrequency) } } +void BladeRF2Input::getFrequencyRange(uint64_t& min, uint64_t& max, int& step) +{ + if (m_deviceShared.m_dev) { + m_deviceShared.m_dev->getFrequencyRangeRx(min, max, step); + } +} + +void BladeRF2Input::getSampleRateRange(int& min, int& max, int& step) +{ + if (m_deviceShared.m_dev) { + m_deviceShared.m_dev->getSampleRateRangeRx(min, max, step); + } +} + +void BladeRF2Input::getBandwidthRange(int& min, int& max, int& step) +{ + if (m_deviceShared.m_dev) { + m_deviceShared.m_dev->getBandwidthRangeRx(min, max, step); + } +} + +void BladeRF2Input::getGlobalGainRange(int& min, int& max, int& step) +{ + if (m_deviceShared.m_dev) { + m_deviceShared.m_dev->getGlobalGainRangeRx(min, max, step); + } +} + bool BladeRF2Input::handleMessage(const Message& message) { if (MsgConfigureBladeRF2::match(message)) @@ -930,4 +958,4 @@ int BladeRF2Input::webapiRun( } return 200; -} \ No newline at end of file +} diff --git a/plugins/samplesource/bladerf2input/bladerf2input.h b/plugins/samplesource/bladerf2input/bladerf2input.h index 5798caf25..8966c378d 100644 --- a/plugins/samplesource/bladerf2input/bladerf2input.h +++ b/plugins/samplesource/bladerf2input/bladerf2input.h @@ -110,6 +110,11 @@ public: virtual quint64 getCenterFrequency() const; virtual void setCenterFrequency(qint64 centerFrequency); + void getFrequencyRange(uint64_t& min, uint64_t& max, int& step); + void getSampleRateRange(int& min, int& max, int& step); + void getBandwidthRange(int& min, int& max, int& step); + void getGlobalGainRange(int& min, int& max, int& step); + virtual bool handleMessage(const Message& message); virtual int webapiSettingsGet( diff --git a/plugins/samplesource/bladerf2input/bladerf2inputgui.cpp b/plugins/samplesource/bladerf2input/bladerf2inputgui.cpp new file mode 100644 index 000000000..3fb1020e9 --- /dev/null +++ b/plugins/samplesource/bladerf2input/bladerf2inputgui.cpp @@ -0,0 +1,333 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + +#include "ui_bladerf2inputgui.h" +#include "gui/colormapper.h" +#include "gui/glspectrum.h" +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "device/devicesourceapi.h" +#include "device/deviceuiset.h" + +#include "bladerf2inputgui.h" + +BladeRF2InputGui::BladeRF2InputGui(DeviceUISet *deviceUISet, QWidget* parent) : + QWidget(parent), + ui(new Ui::Bladerf2InputGui), + m_deviceUISet(deviceUISet), + m_forceSettings(true), + m_doApplySettings(true), + m_settings(), + m_sampleSource(0), + m_sampleRate(0), + m_lastEngineState(DSPDeviceSourceEngine::StNotStarted) +{ + m_sampleSource = (BladeRF2Input*) m_deviceUISet->m_deviceSourceAPI->getSampleSource(); + int max, min, step; + uint64_t f_min, f_max; + + ui->setupUi(this); + + m_sampleSource->getFrequencyRange(f_min, f_max, step); + ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000); + + m_sampleSource->getSampleRateRange(min, max, step); + ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); + ui->sampleRate->setValueRange(8, min, max); + + m_sampleSource->getBandwidthRange(min, max, step); + ui->bandwidth->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); + ui->bandwidth->setValueRange(6, min/1000, max/1000); + + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); + connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); + m_statusTimer.start(500); + + displaySettings(); + + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); + m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); + + sendSettings(); +} + +BladeRF2InputGui::~BladeRF2InputGui() +{ + delete ui; +} + +void BladeRF2InputGui::destroy() +{ + delete this; +} + +void BladeRF2InputGui::setName(const QString& name) +{ + setObjectName(name); +} + +QString BladeRF2InputGui::getName() const +{ + return objectName(); +} + +void BladeRF2InputGui::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + sendSettings(); +} + +qint64 BladeRF2InputGui::getCenterFrequency() const +{ + return m_settings.m_centerFrequency; +} + +void BladeRF2InputGui::setCenterFrequency(qint64 centerFrequency) +{ + m_settings.m_centerFrequency = centerFrequency; + displaySettings(); + sendSettings(); +} + +QByteArray BladeRF2InputGui::serialize() const +{ + return m_settings.serialize(); +} + +bool BladeRF2InputGui::deserialize(const QByteArray& data) +{ + if(m_settings.deserialize(data)) { + displaySettings(); + m_forceSettings = true; + sendSettings(); + return true; + } else { + resetToDefaults(); + return false; + } +} + +bool BladeRF2InputGui::handleMessage(const Message& message) +{ + if (BladeRF2Input::MsgConfigureBladeRF2::match(message)) + { + const BladeRF2Input::MsgConfigureBladeRF2& cfg = (BladeRF2Input::MsgConfigureBladeRF2&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + displaySettings(); + blockApplySettings(false); + return true; + } + else if (BladeRF2Input::MsgStartStop::match(message)) + { + BladeRF2Input::MsgStartStop& notif = (BladeRF2Input::MsgStartStop&) message; + blockApplySettings(true); + ui->startStop->setChecked(notif.getStartStop()); + blockApplySettings(false); + + return true; + } + else + { + return false; + } +} + +void BladeRF2InputGui::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != 0) + { + qDebug("BladeRF2InputGui::handleInputMessages: message: %s", message->getIdentifier()); + + if (DSPSignalNotification::match(*message)) + { + DSPSignalNotification* notif = (DSPSignalNotification*) message; + m_sampleRate = notif->getSampleRate(); + m_deviceCenterFrequency = notif->getCenterFrequency(); + qDebug("BladeRF2InputGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency()); + updateSampleRateAndFrequency(); + + delete message; + } + else + { + if (handleMessage(*message)) + { + delete message; + } + } + } +} + +void BladeRF2InputGui::updateSampleRateAndFrequency() +{ + m_deviceUISet->getSpectrum()->setSampleRate(m_sampleRate); + m_deviceUISet->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency); + ui->deviceRateLabel->setText(tr("%1k").arg(QString::number(m_sampleRate / 1000.0f, 'g', 5))); +} + +void BladeRF2InputGui::displaySettings() +{ + blockApplySettings(true); + + ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); + ui->sampleRate->setValue(m_settings.m_devSampleRate); + ui->bandwidth->setValue(m_settings.m_bandwidth / 1000); + + ui->dcOffset->setChecked(m_settings.m_dcBlock); + ui->iqImbalance->setChecked(m_settings.m_iqCorrection); + + ui->decim->setCurrentIndex(m_settings.m_log2Decim); + ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos); + + ui->gain->setValue(m_settings.m_globalGain); + + blockApplySettings(false); +} + +void BladeRF2InputGui::sendSettings() +{ + if(!m_updateTimer.isActive()) + m_updateTimer.start(100); +} + +void BladeRF2InputGui::on_centerFrequency_changed(quint64 value) +{ + m_settings.m_centerFrequency = value * 1000; + sendSettings(); +} + +void BladeRF2InputGui::on_sampleRate_changed(quint64 value) +{ + m_settings.m_devSampleRate = value; + sendSettings(); +} + +void BladeRF2InputGui::on_dcOffset_toggled(bool checked) +{ + m_settings.m_dcBlock = checked; + sendSettings(); +} + +void BladeRF2InputGui::on_iqImbalance_toggled(bool checked) +{ + m_settings.m_iqCorrection = checked; + sendSettings(); +} + +void BladeRF2InputGui::on_bandwidth_changed(quint64 value) +{ + m_settings.m_bandwidth = value * 1000; + sendSettings(); +} + +void BladeRF2InputGui::on_decim_currentIndexChanged(int index) +{ + if ((index <0) || (index > 6)) + return; + m_settings.m_log2Decim = index; + sendSettings(); +} + +void BladeRF2InputGui::on_fcPos_currentIndexChanged(int index) +{ + if (index == 0) { + m_settings.m_fcPos = BladeRF2InputSettings::FC_POS_INFRA; + sendSettings(); + } else if (index == 1) { + m_settings.m_fcPos = BladeRF2InputSettings::FC_POS_SUPRA; + sendSettings(); + } else if (index == 2) { + m_settings.m_fcPos = BladeRF2InputSettings::FC_POS_CENTER; + sendSettings(); + } +} + +void BladeRF2InputGui::on_startStop_toggled(bool checked) +{ + if (m_doApplySettings) + { + BladeRF2Input::MsgStartStop *message = BladeRF2Input::MsgStartStop::create(checked); + m_sampleSource->getInputMessageQueue()->push(message); + } +} + +void BladeRF2InputGui::on_record_toggled(bool checked) +{ + if (checked) { + ui->record->setStyleSheet("QToolButton { background-color : red; }"); + } else { + ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + } + + BladeRF2Input::MsgFileRecord* message = BladeRF2Input::MsgFileRecord::create(checked); + m_sampleSource->getInputMessageQueue()->push(message); +} + +void BladeRF2InputGui::updateHardware() +{ + if (m_doApplySettings) + { + qDebug() << "BladeRF2InputGui::updateHardware"; + BladeRF2Input::MsgConfigureBladeRF2* message = BladeRF2Input::MsgConfigureBladeRF2::create(m_settings, m_forceSettings); + m_sampleSource->getInputMessageQueue()->push(message); + m_forceSettings = false; + m_updateTimer.stop(); + } +} + +void BladeRF2InputGui::blockApplySettings(bool block) +{ + m_doApplySettings = !block; +} + +void BladeRF2InputGui::updateStatus() +{ + int state = m_deviceUISet->m_deviceSourceAPI->state(); + + if(m_lastEngineState != state) + { + switch(state) + { + case DSPDeviceSourceEngine::StNotStarted: + ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + break; + case DSPDeviceSourceEngine::StIdle: + ui->startStop->setStyleSheet("QToolButton { background-color : blue; }"); + break; + case DSPDeviceSourceEngine::StRunning: + ui->startStop->setStyleSheet("QToolButton { background-color : green; }"); + break; + case DSPDeviceSourceEngine::StError: + ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); + QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceSourceAPI->errorMessage()); + break; + default: + break; + } + + m_lastEngineState = state; + } +} diff --git a/plugins/samplesource/bladerf2input/bladerf2inputgui.h b/plugins/samplesource/bladerf2input/bladerf2inputgui.h new file mode 100644 index 000000000..f52c82022 --- /dev/null +++ b/plugins/samplesource/bladerf2input/bladerf2inputgui.h @@ -0,0 +1,93 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUTGUI_H_ +#define PLUGINS_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUTGUI_H_ + +#include +#include +#include + +#include "util/messagequeue.h" + +#include "bladerf2input.h" + +class DeviceUISet; + +namespace Ui { + class Bladerf2InputGui; +} + +class BladeRF2InputGui : public QWidget, public PluginInstanceGUI { + Q_OBJECT + +public: + explicit BladeRF2InputGui(DeviceUISet *deviceUISet, QWidget* parent = 0); + virtual ~BladeRF2InputGui(); + virtual void destroy(); + + void setName(const QString& name); + QString getName() const; + + void resetToDefaults(); + virtual qint64 getCenterFrequency() const; + virtual void setCenterFrequency(qint64 centerFrequency); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual bool handleMessage(const Message& message); + +private: + Ui::Bladerf2InputGui* ui; + + DeviceUISet* m_deviceUISet; + bool m_forceSettings; + bool m_doApplySettings; + BladeRF2InputSettings m_settings; + QTimer m_updateTimer; + QTimer m_statusTimer; + std::vector m_gains; + BladeRF2Input* m_sampleSource; + int m_sampleRate; + quint64 m_deviceCenterFrequency; //!< Center frequency in device + int m_lastEngineState; + MessageQueue m_inputMessageQueue; + + void displaySettings(); + void sendSettings(); + void updateSampleRateAndFrequency(); + void blockApplySettings(bool block); + +private slots: + void handleInputMessages(); + void on_centerFrequency_changed(quint64 value); + void on_sampleRate_changed(quint64 value); + void on_dcOffset_toggled(bool checked); + void on_iqImbalance_toggled(bool checked); + void on_biasTee_toggled(bool checked); + void on_bandwidth_changed(quint64 value); + void on_decim_currentIndexChanged(int index); + void on_fcPos_currentIndexChanged(int index); + void on_gainMode_currentIndexChanged(int index); + void on_gain_valueChanged(int value); + void on_startStop_toggled(bool checked); + void on_record_toggled(bool checked); + void updateHardware(); + void updateStatus(); + +}; + +#endif /* PLUGINS_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUTGUI_H_ */ diff --git a/plugins/samplesource/bladerf2input/bladerf2inputgui.ui b/plugins/samplesource/bladerf2input/bladerf2inputgui.ui index 527110d64..b39e828d9 100644 --- a/plugins/samplesource/bladerf2input/bladerf2inputgui.ui +++ b/plugins/samplesource/bladerf2input/bladerf2inputgui.ui @@ -7,7 +7,7 @@ 0 0 310 - 265 + 250 @@ -222,67 +222,59 @@ - - + + - xb200 + kHz + + + + + + + + 0 + 0 + + + + BW - + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + + + - XB200 board mode + Bias Tee - - None + + BT - - 0 - - - 5 - - - - None - - - - - Bypass - - - - - Auto 1dB - - - - - Auto 3dB - - - - - Custom - - - - - 50M - - - - - 144M - - - - - 222M - - @@ -360,6 +352,35 @@ + + + + Fp + + + + + + + Relative position of device center frequency + + + + Inf + + + + + Sup + + + + + Cen + + + + @@ -421,146 +442,43 @@ - + 3 - - + + Qt::Horizontal - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - BW - - - + + + + + - Fp + Gain - - - Relative position of device center frequency - - - - Inf - - - - - Sup - - - - - Cen - - - - - - - - - 0 - 0 - + + + + 25 + 0 + - LNA + 000 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - 40 - 16777215 - - - - - 0 - - - - - 3 - - - - - 6 - - - - - - - - dB - - - - - - - kHz - - - - - - - - 70 - 16777215 - - - - IF bandwidth in kHz - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -570,117 +488,6 @@ - - - - 3 - - - - - Amplifier before filtering gain (dB) - - - 5 - - - 30 - - - 1 - - - 20 - - - Qt::Horizontal - - - - - - - - 40 - 0 - - - - 20 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - VGA1 - - - - - - - - - Qt::Horizontal - - - - - - - 3 - - - - - VGA2 - - - - - - - Amplifier before ADC gain (dB) - - - 30 - - - 3 - - - 3 - - - 9 - - - Qt::Horizontal - - - - - - - - 40 - 0 - - - - 9 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - @@ -698,13 +505,6 @@ - - - - Qt::Horizontal - - - diff --git a/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp b/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp index db6b282c4..76a611e62 100644 --- a/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp +++ b/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp @@ -87,7 +87,7 @@ PluginInterface::SamplingDevices Blderf2InputPlugin::enumSampleSources() { unsigned int nbRxChannels = bladerf_get_channel_count(dev, BLADERF_RX); - for (int j = 0; j < nbRxChannels; j++) + for (unsigned int j = 0; j < nbRxChannels; j++) { qDebug("Blderf2InputPlugin::enumSampleSources: device #%d (%s) channel %u", i, devinfo[i].serial, j); QString displayedName(QString("BladeRF2[%1:%2] %3").arg(devinfo[i].instance).arg(j).arg(devinfo[i].serial)); @@ -128,7 +128,7 @@ PluginInstanceGUI* Blderf2InputPlugin::createSampleSourcePluginInstanceGUI( { if(sourceId == m_deviceTypeID) { - Bladerf2InputGui* gui = new Bladerf2InputGui(deviceUISet); + BladeRF2InputGui* gui = new BladeRF2InputGui(deviceUISet); *widget = gui; return gui; } @@ -143,7 +143,7 @@ DeviceSampleSource *Blderf2InputPlugin::createSampleSourcePluginInstanceInput(co { if (sourceId == m_deviceTypeID) { - Bladerf2Input *input = new Bladerf2Input(deviceAPI); + BladeRF2Input *input = new BladeRF2Input(deviceAPI); return input; } else diff --git a/udev-rules/88-nuand.rules b/udev-rules/88-nuand.rules index c8d182dd4..44add41f7 100644 --- a/udev-rules/88-nuand.rules +++ b/udev-rules/88-nuand.rules @@ -1,6 +1,9 @@ # Nuand bladeRF ATTR{idVendor}=="2cf0", ATTR{idProduct}=="5246", MODE="666", GROUP="plugdev" +# Nuand bladeRF2 +ATTR{idVendor}=="2cf0", ATTR{idProduct}=="5250", MODE="666", GROUP="plugdev" + # Nuand bladeRF, legacy VID/PID ATTR{idVendor}=="1d50", ATTR{idProduct}=="6066", MODE="666", GROUP="plugdev"