diff --git a/devices/limesdr/CMakeLists.txt b/devices/limesdr/CMakeLists.txt
index 6856b1e72..0313da1f3 100644
--- a/devices/limesdr/CMakeLists.txt
+++ b/devices/limesdr/CMakeLists.txt
@@ -1,10 +1,12 @@
project(limesdrdevice)
set(limesdrdevice_SOURCES
+ devicelimesdr.cpp
devicelimesdrparam.cpp
)
set(limesdrdevice_HEADERS
+ devicelimesdr.h
devicelimesdrparam.h
)
diff --git a/devices/limesdr/devicelimesdr.cpp b/devices/limesdr/devicelimesdr.cpp
new file mode 100644
index 000000000..90931fcad
--- /dev/null
+++ b/devices/limesdr/devicelimesdr.cpp
@@ -0,0 +1,167 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 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 "devicelimesdr.h"
+
+bool DeviceLimeSDR::enableNCO(lms_device_t *device, bool dir_tx, std::size_t chan, float frequency, bool enable)
+{
+ if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::enableNCO: cannot address channel #%lu\n", chan);
+ return false;
+ }
+
+ if (dir_tx)
+ {
+ if (LMS_WriteParam(device, LMS7param(CMIX_BYP_RXTSP), enable ? 0 : 1) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::enableNCO: cannot %s Rx NCO\n", enable ? "enable" : "disable");
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (LMS_WriteParam(device, LMS7param(CMIX_BYP_TXTSP), enable ? 0 : 1) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::enableNCO: cannot %s Tx NCO\n", enable ? "enable" : "disable");
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+}
+
+bool DeviceLimeSDR::setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, float frequency)
+{
+ bool positive;
+ float freqs[LMS_NCO_VAL_COUNT];
+ float phos[LMS_NCO_VAL_COUNT];
+
+ if (LMS_GetNCOFrequency(device, dir_tx, chan, freqs, phos) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot get NCO frequencies and phases\n");
+ }
+
+ if (frequency < 0)
+ {
+ positive = false;
+ frequency = -frequency;
+ }
+ else
+ {
+ positive = true;
+ }
+
+ freqs[0] = frequency;
+
+ if (LMS_SetNCOFrequency(device, dir_tx, chan, freqs, phos) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set frequency to %f\n", frequency);
+ return false;
+ }
+
+ if (LMS_SetNCOIndex(device, dir_tx, chan, 0, positive) < 0) // TODO: verify positive = downconvert ?
+ {
+ fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set conversion direction %s\n", positive ? "down" : "up");
+ return false;
+ }
+
+ return true;
+}
+
+bool DeviceLimeSDR::setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable, float frequency)
+{
+ if (enable)
+ {
+ bool positive;
+ float freqs[LMS_NCO_VAL_COUNT];
+ float phos[LMS_NCO_VAL_COUNT];
+
+ if (LMS_GetNCOFrequency(device, dir_tx, chan, freqs, phos) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot get NCO frequencies and phases\n");
+ }
+
+ if (frequency < 0)
+ {
+ positive = false;
+ frequency = -frequency;
+ }
+ else
+ {
+ positive = true;
+ }
+
+ freqs[0] = frequency;
+
+ if (LMS_SetNCOFrequency(device, dir_tx, chan, freqs, phos) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set frequency to %f\n", frequency);
+ return false;
+ }
+
+ if (LMS_SetNCOIndex(device, dir_tx, chan, 0, positive) < 0) // TODO: verify positive = downconvert ?
+ {
+ fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set conversion direction %s\n", positive ? "down" : "up");
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot address channel #%lu\n", chan);
+ return false;
+ }
+
+ if (dir_tx)
+ {
+ if (LMS_WriteParam(device, LMS7param(CMIX_BYP_RXTSP), 1) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::enableNCO: cannot disable Rx NCO on channel %lu\n", chan);
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (LMS_WriteParam(device, LMS7param(CMIX_BYP_TXTSP), 1) < 0)
+ {
+ fprintf(stderr, "DeviceLimeSDR::enableNCO: cannot disable Tx NCO on channel %lu\n", chan);
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+}
+
+
diff --git a/devices/limesdr/devicelimesdr.h b/devices/limesdr/devicelimesdr.h
new file mode 100644
index 000000000..7b7d2202f
--- /dev/null
+++ b/devices/limesdr/devicelimesdr.h
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 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 DEVICES_LIMESDR_DEVICELIMESDR_H_
+#define DEVICES_LIMESDR_DEVICELIMESDR_H_
+
+#include "lime/LimeSuite.h"
+
+class DeviceLimeSDR
+{
+public:
+ /** enable or disable NCO. If re-enabled frequency should have been set once */
+ static bool enableNCO(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable);
+ /** set NCO frequency with positive or negative frequency (deals with up/down convert). Enables NCO */
+ static bool setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, float frequency);
+ /** combination of the two like LMS_SetGFIRLPF */
+ static bool setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable, float frequency);
+};
+
+#endif /* DEVICES_LIMESDR_DEVICELIMESDR_H_ */
diff --git a/plugins/samplesource/limesdrinput/limesdrinput.cpp b/plugins/samplesource/limesdrinput/limesdrinput.cpp
index 3eb448dd2..e3f6def3d 100644
--- a/plugins/samplesource/limesdrinput/limesdrinput.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinput.cpp
@@ -26,6 +26,7 @@
#include "limesdrinput.h"
#include "limesdrinputthread.h"
#include "limesdr/devicelimesdrparam.h"
+#include "limesdr/devicelimesdr.h"
MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgConfigureLimeSDR, Message)
MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgGetStreamInfo, Message)
@@ -457,7 +458,9 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
if ((m_settings.m_gain != settings.m_gain) ||
(m_settings.m_lpfBW != settings.m_lpfBW) ||
(m_settings.m_lpfFIRBW != settings.m_lpfFIRBW) ||
- (m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) || force)
+ (m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) ||
+ (m_settings.m_ncoEnable != settings.m_ncoEnable) ||
+ (m_settings.m_ncoFrequency != settings.m_ncoFrequency) || force)
{
suspendOwnThread = true;
}
@@ -648,6 +651,34 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
}
}
+ if ((m_settings.m_ncoFrequency != settings.m_ncoFrequency) ||
+ (m_settings.m_ncoEnable != settings.m_ncoEnable) || force)
+ {
+ m_settings.m_ncoFrequency = settings.m_ncoFrequency;
+ m_settings.m_ncoEnable = settings.m_ncoEnable;
+
+ if (m_deviceShared.m_deviceParams->getDevice() != 0)
+ {
+ if (DeviceLimeSDR::setNCOFrequency(m_deviceShared.m_deviceParams->getDevice(),
+ LMS_CH_RX,
+ m_deviceShared.m_channel,
+ m_settings.m_ncoEnable,
+ m_settings.m_ncoFrequency))
+ {
+ doCalibration = true;
+ qDebug("LimeSDRInput::applySettings: %sd and set NCO to %f Hz",
+ m_settings.m_ncoEnable ? "enable" : "disable",
+ m_settings.m_ncoFrequency);
+ }
+ else
+ {
+ qCritical("LimeSDRInput::applySettings: could %s and set LPF FIR to %f Hz",
+ m_settings.m_ncoEnable ? "enable" : "disable",
+ m_settings.m_ncoFrequency);
+ }
+ }
+ }
+
if ((m_settings.m_log2SoftDecim != settings.m_log2SoftDecim) || force)
{
m_settings.m_log2SoftDecim = settings.m_log2SoftDecim;
@@ -682,6 +713,7 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
}
}
+
if (doCalibration)
{
if (LMS_Calibrate(m_deviceShared.m_deviceParams->getDevice(),
diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp
index aab39ff83..87a366af2 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp
@@ -61,6 +61,8 @@ LimeSDRInputGUI::LimeSDRInputGUI(DeviceSourceAPI *deviceAPI, QWidget* parent) :
ui->lpFIR->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
ui->lpFIR->setValueRange(5, 1U, 56000U);
+ ui->ncoFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
+
ui->channelNumberText->setText(tr("#%1").arg(m_limeSDRInput->getChannelIndex()));
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
@@ -244,6 +246,12 @@ void LimeSDRInputGUI::displaySettings()
ui->gain->setValue(m_settings.m_gain);
ui->gainText->setText(tr("%1dB").arg(m_settings.m_gain));
+
+ int ncoHalfRange = (m_settings.m_devSampleRate * (1<<(m_settings.m_log2HardDecim)))/2;
+ ui->ncoFrequency->setValueRange(7,
+ (m_settings.m_centerFrequency - ncoHalfRange)/1000,
+ (m_settings.m_centerFrequency + ncoHalfRange)/1000); // frequency dial is in kHz
+ ui->ncoFrequency->setValue(m_settings.m_centerFrequency + m_settings.m_ncoFrequency);
}
void LimeSDRInputGUI::sendSettings()
@@ -345,6 +353,25 @@ void LimeSDRInputGUI::on_centerFrequency_changed(quint64 value)
sendSettings();
}
+void LimeSDRInputGUI::on_ncoFrequency_changed(quint64 value)
+{
+ m_settings.m_ncoFrequency = (int64_t) value - (int64_t) m_settings.m_centerFrequency;
+ sendSettings();
+}
+
+void LimeSDRInputGUI::on_ncoEnable_toggled(bool checked)
+{
+ m_settings.m_ncoEnable = checked;
+ sendSettings();
+}
+
+void LimeSDRInputGUI::on_ncoReset_clicked(bool checked)
+{
+ m_settings.m_ncoFrequency = 0;
+ ui->ncoFrequency->setValue(m_settings.m_centerFrequency);
+ sendSettings();
+}
+
void LimeSDRInputGUI::on_dcOffset_toggled(bool checked)
{
m_settings.m_dcBlock = checked;
@@ -393,7 +420,10 @@ void LimeSDRInputGUI::on_lpFIREnable_toggled(bool checked)
void LimeSDRInputGUI::on_lpFIR_changed(quint64 value)
{
m_settings.m_lpfFIRBW = value * 1000;
- sendSettings();
+
+ if (m_settings.m_lpfFIREnable) { // do not send the update if the FIR is disabled
+ sendSettings();
+ }
}
void LimeSDRInputGUI::on_gain_valueChanged(int value)
diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.h b/plugins/samplesource/limesdrinput/limesdrinputgui.h
index 28fa87a6c..bffdc9e91 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputgui.h
+++ b/plugins/samplesource/limesdrinput/limesdrinputgui.h
@@ -74,6 +74,9 @@ private slots:
void on_startStop_toggled(bool checked);
void on_record_toggled(bool checked);
void on_centerFrequency_changed(quint64 value);
+ void on_ncoFrequency_changed(quint64 value);
+ void on_ncoEnable_toggled(bool checked);
+ void on_ncoReset_clicked(bool checked);
void on_dcOffset_toggled(bool checked);
void on_iqImbalance_toggled(bool checked);
void on_sampleRate_changed(quint64 value);
diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.ui b/plugins/samplesource/limesdrinput/limesdrinputgui.ui
index 5c3453348..7d7b825e2 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputgui.ui
+++ b/plugins/samplesource/limesdrinput/limesdrinputgui.ui
@@ -29,7 +29,7 @@
- BladeRF
+ LimeSDR Input
@@ -190,43 +190,79 @@
-
-
-
- Qt::Horizontal
+
+
+ 6
-
-
- -
-
-
-
-
-
- S/s
-
-
-
- -
-
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
- Automatic IQ imbalance correction
+ Enable the TSP NCO
- IQ
+ NCO
- -
-
+
-
+
+
+
+ 22
+ 22
+
+
- Automatic DC offset removal
+ Reset the NCO to zero frequency
- DC
+ R
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ Monospace
+ 12
+
+
+
+ Center frequency with NCO engaged (kHz)
+
+
+
+ -
+
+
+ kHz
+
+
+
+ -
+
Qt::Horizontal
@@ -238,14 +274,20 @@
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
- Auto
+ SR
- -
+
-
@@ -267,16 +309,10 @@
- -
-
-
-
- 0
- 0
-
-
+
-
+
- SR
+ S/s
@@ -290,13 +326,47 @@
-
-
+
2
2
+
-
+
+
+ Auto
+
+
+
+ -
+
+
+ Automatic DC offset removal
+
+
+ DC
+
+
+
+ -
+
+
+ Automatic IQ imbalance correction
+
+
+ IQ
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
-
@@ -422,13 +492,6 @@
- -
-
-
- Qt::Horizontal
-
-
-
-
@@ -539,6 +602,13 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
-
-
@@ -591,6 +661,13 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
-
diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp
index 796064049..0da40ff7e 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp
+++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp
@@ -35,6 +35,8 @@ void LimeSDRInputSettings::resetToDefaults()
m_lpfFIREnable = false;
m_lpfFIRBW = 2.5e6f;
m_gain = 30;
+ m_ncoEnable = false;
+ m_ncoFrequency = 0;
}
QByteArray LimeSDRInputSettings::serialize() const
diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.h b/plugins/samplesource/limesdrinput/limesdrinputsettings.h
index c87f84291..548329184 100644
--- a/plugins/samplesource/limesdrinput/limesdrinputsettings.h
+++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.h
@@ -45,6 +45,8 @@ struct LimeSDRInputSettings
bool m_lpfFIREnable; //!< Enable LMS digital lowpass FIR filters
float m_lpfFIRBW; //!< LMS digital lowpass FIR filters bandwidth (Hz)
uint32_t m_gain; //!< Optimally distributed gain (dB)
+ bool m_ncoEnable; //!< Enable TSP NCO and mixing
+ int m_ncoFrequency; //!< Actual NCO frequency (the resulting frequency with mixing is displayed)
LimeSDRInputSettings();
void resetToDefaults();