diff --git a/cmake/Modules/FindLibXTRX.cmake b/cmake/Modules/FindLibXTRX.cmake
new file mode 100644
index 000000000..ade45c76c
--- /dev/null
+++ b/cmake/Modules/FindLibXTRX.cmake
@@ -0,0 +1,27 @@
+if(NOT LIBXTRX_FOUND)
+ pkg_check_modules (LIBXTRX_PKG libxtrx)
+ find_path(LIBXTRX_INCLUDE_DIRS NAMES xtrx_api.h
+ PATHS
+ ${LIBXTRX_PKG_INCLUDE_DIRS}
+ /usr/include
+ /usr/local/include
+ )
+
+ find_library(LIBXTRX_LIBRARIES NAMES xtrx
+ PATHS
+ ${LIBXTRX_PKG_LIBRARY_DIRS}
+ /usr/lib
+ /usr/local/lib
+ )
+
+if(LIBXTRX_INCLUDE_DIRS AND LIBXTRX_LIBRARIES)
+ set(LIBXTRX_FOUND TRUE CACHE INTERNAL "libxtrx found")
+ message(STATUS "Found libxtrx: ${LIBXTRX_INCLUDE_DIRS}, ${LIBXTRX_LIBRARIES}")
+else(LIBXTRX_INCLUDE_DIRS AND LIBXTRX_LIBRARIES)
+ set(LIBXTRX_FOUND FALSE CACHE INTERNAL "libxtrx found")
+ message(STATUS "libxtrx not found.")
+endif(LIBXTRX_INCLUDE_DIRS AND LIBXTRX_LIBRARIES)
+
+mark_as_advanced(LIBXTRX_LIBRARIES LIBXTRX_INCLUDE_DIRS)
+
+endif(NOT LIBXTRX_FOUND)
\ No newline at end of file
diff --git a/devices/CMakeLists.txt b/devices/CMakeLists.txt
index 422cc588b..8c3de333a 100644
--- a/devices/CMakeLists.txt
+++ b/devices/CMakeLists.txt
@@ -12,6 +12,7 @@ if (BUILD_DEBIAN)
add_subdirectory(perseus)
add_subdirectory(plutosdr)
add_subdirectory(soapysdr)
+ add_subdirectory(xtrx)
else(BUILD_DEBIAN)
find_package(LibBLADERF)
if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
@@ -29,6 +30,11 @@ else(BUILD_DEBIAN)
add_subdirectory(limesdr)
endif(LIBUSB_FOUND AND LIMESUITE_FOUND)
+ find_package(LibXTRX)
+ if(LIBXTRX_FOUND)
+ add_subdirectory(xtrx)
+ endif(LIBXTRX_FOUND)
+
find_package(LibIIO)
if(LIBUSB_FOUND AND LIBIIO_FOUND)
add_subdirectory(plutosdr)
diff --git a/devices/xtrx/CMakeLists.txt b/devices/xtrx/CMakeLists.txt
new file mode 100644
index 000000000..189c1b534
--- /dev/null
+++ b/devices/xtrx/CMakeLists.txt
@@ -0,0 +1,31 @@
+project(xtrxdevice)
+
+set(xtrxdevice_SOURCES
+ devicextrxparam.cpp
+ devicextrxshared.cpp
+)
+
+set(xtrxdevice_HEADERS
+ devicextrxparam.h
+ devicextrxshared.h
+)
+
+include_directories(
+ .
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${LIBXTRX_INCLUDE_DIRS}
+)
+
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_SHARED)
+
+add_library(xtrxdevice SHARED
+ ${xtrxdevice_SOURCES}
+)
+
+target_link_libraries(xtrxdevice
+ ${LIBXTRX_LIBRARIES}
+ sdrbase
+)
+
+install(TARGETS xtrxdevice DESTINATION lib)
diff --git a/devices/xtrx/devicextrxparam.cpp b/devices/xtrx/devicextrxparam.cpp
new file mode 100644
index 000000000..249656412
--- /dev/null
+++ b/devices/xtrx/devicextrxparam.cpp
@@ -0,0 +1,44 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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 "devicextrxparam.h"
+
+bool DeviceXTRXParams::open(const char* deviceStr)
+{
+ int res;
+ qDebug("DeviceXTRXParams::open: serial: %s", (const char *) deviceStr);
+
+ res = xtrx_open(deviceStr, XTRX_O_RESET | 4, &m_dev);
+
+ if (res)
+ {
+ qCritical() << "DeviceXTRXParams::open: cannot open device " << deviceStr;
+ return false;
+ }
+
+
+ return true;
+}
+
+void DeviceXTRXParams::close()
+{
+ if (m_dev)
+ {
+ xtrx_close(m_dev);
+ m_dev = 0;
+ }
+}
diff --git a/devices/xtrx/devicextrxparam.h b/devices/xtrx/devicextrxparam.h
new file mode 100644
index 000000000..c7e2b4233
--- /dev/null
+++ b/devices/xtrx/devicextrxparam.h
@@ -0,0 +1,58 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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_XTRX_DEVICEXTRXPARAM_H_
+#define DEVICES_XTRX_DEVICEXTRXPARAM_H_
+
+#include "xtrx_api.h"
+
+
+struct DeviceXTRXParams
+{
+ struct xtrx_dev *m_dev; //!< device handle
+ uint32_t m_nbRxChannels; //!< number of Rx channels
+ uint32_t m_nbTxChannels; //!< number of Tx channels
+
+ unsigned m_log2OvSRRx;
+ double m_sampleRate; //!< ADC/DAC sample rate
+ double m_rxFrequency; //!< Rx frequency
+ double m_txFrequency; //!< Tx frequency
+
+ DeviceXTRXParams() :
+ m_dev(0),
+ m_nbRxChannels(2),
+ m_nbTxChannels(2),
+ m_log2OvSRRx(0),
+ m_sampleRate(5e6),
+ m_rxFrequency(30e6),
+ m_txFrequency(30e6)
+ {
+ }
+
+ /**
+ * Opens and initialize the device and obtain information (# channels, ranges, ...)
+ */
+ bool open(const char* deviceStr);
+ void close();
+
+ struct xtrx_dev *getDevice() { return m_dev; }
+
+ ~DeviceXTRXParams()
+ {
+ }
+};
+
+#endif /* DEVICES_XTRX_DEVICEXTRXPARAM_H_ */
diff --git a/devices/xtrx/devicextrxshared.cpp b/devices/xtrx/devicextrxshared.cpp
new file mode 100644
index 000000000..4ae1f7c81
--- /dev/null
+++ b/devices/xtrx/devicextrxshared.cpp
@@ -0,0 +1,83 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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 "devicextrxshared.h"
+
+MESSAGE_CLASS_DEFINITION(DeviceXTRXShared::MsgReportBuddyChange, Message)
+MESSAGE_CLASS_DEFINITION(DeviceXTRXShared::MsgReportClockSourceChange, Message)
+MESSAGE_CLASS_DEFINITION(DeviceXTRXShared::MsgReportDeviceInfo, Message)
+
+const float DeviceXTRXShared::m_sampleFifoLengthInSeconds = 0.25;
+const int DeviceXTRXShared::m_sampleFifoMinSize = 48000; // 192kS/s knee
+
+
+
+double DeviceXTRXShared::set_samplerate(double rate,
+ double master,
+ bool output)
+{
+ if (output)
+ {
+ m_outputRate = rate;
+
+ if (master != 0.0) {
+ m_masterRate = master;
+ }
+ }
+ else
+ {
+ m_inputRate = rate;
+
+ if (master != 0.0) {
+ m_masterRate = master;
+ }
+ }
+
+ int res = xtrx_set_samplerate(m_deviceParams->getDevice(),
+ m_masterRate,
+ m_inputRate,
+ m_outputRate,
+ 0,
+ 0,
+ 0,
+ 0);
+
+ if (res) {
+ //fprintf(stderr, "Unable to set samplerate, error=%d\n", res);
+ return 0;
+ }
+
+ if (output) {
+ return m_outputRate;
+ }
+
+ return m_inputRate;
+}
+
+double DeviceXTRXShared::get_temperature()
+{
+ uint64_t val = 0;
+
+ int res = xtrx_val_get(m_deviceParams->getDevice(),
+ XTRX_TRX, XTRX_CH_AB, XTRX_BOARD_TEMP, &val);
+
+ if (res) {
+ //fprintf(stderr, "Unable to set samplerate, error=%d\n", res);
+ return 0;
+ }
+
+ return val;
+}
diff --git a/devices/xtrx/devicextrxshared.h b/devices/xtrx/devicextrxshared.h
new file mode 100644
index 000000000..b1441e815
--- /dev/null
+++ b/devices/xtrx/devicextrxshared.h
@@ -0,0 +1,165 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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_DEVICELIMESDRSHARED_H_
+#define DEVICES_LIMESDR_DEVICELIMESDRSHARED_H_
+
+#include
+#include "devicextrxparam.h"
+#include "util/message.h"
+
+/**
+ * Structure shared by a buddy with other buddies
+ */
+class DeviceXTRXShared
+{
+public:
+ class MsgReportBuddyChange : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ int getDevSampleRate() const { return m_devSampleRate; }
+ unsigned getLog2HardDecimInterp() const { return m_log2HardDecimInterp; }
+ uint64_t getCenterFrequency() const { return m_centerFrequency; }
+ bool getRxElseTx() const { return m_rxElseTx; }
+
+ static MsgReportBuddyChange* create(
+ int devSampleRate,
+ unsigned log2HardDecimInterp,
+ uint64_t centerFrequency,
+ bool rxElseTx)
+ {
+ return new MsgReportBuddyChange(
+ devSampleRate,
+ log2HardDecimInterp,
+ centerFrequency,
+ rxElseTx);
+ }
+
+ private:
+ int m_devSampleRate; //!< device/host sample rate
+ unsigned m_log2HardDecimInterp; //!< log2 of hardware decimation or interpolation
+ uint64_t m_centerFrequency; //!< Center frequency
+ bool m_rxElseTx; //!< tells which side initiated the message
+
+ MsgReportBuddyChange(
+ int devSampleRate,
+ unsigned log2HardDecimInterp,
+ uint64_t centerFrequency,
+ bool rxElseTx) :
+ Message(),
+ m_devSampleRate(devSampleRate),
+ m_log2HardDecimInterp(log2HardDecimInterp),
+ m_centerFrequency(centerFrequency),
+ m_rxElseTx(rxElseTx)
+ { }
+ };
+
+ class MsgReportClockSourceChange : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ bool getExtClock() const { return m_extClock; }
+ uint32_t getExtClockFeq() const { return m_extClockFreq; }
+
+ static MsgReportClockSourceChange* create(
+ bool extClock,
+ uint32_t m_extClockFreq)
+ {
+ return new MsgReportClockSourceChange(
+ extClock,
+ m_extClockFreq);
+ }
+
+ private:
+ bool m_extClock; //!< True if external clock source
+ uint32_t m_extClockFreq; //!< Frequency (Hz) of external clock source
+
+ MsgReportClockSourceChange(
+ bool extClock,
+ uint32_t m_extClockFreq) :
+ Message(),
+ m_extClock(extClock),
+ m_extClockFreq(m_extClockFreq)
+ { }
+ };
+
+ class MsgReportDeviceInfo : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ float getTemperature() const { return m_temperature; }
+
+ static MsgReportDeviceInfo* create(float temperature)
+ {
+ return new MsgReportDeviceInfo(temperature);
+ }
+
+ private:
+ float m_temperature;
+
+ MsgReportDeviceInfo(float temperature) :
+ Message(),
+ m_temperature(temperature)
+ { }
+ };
+
+ class ThreadInterface
+ {
+ public:
+ virtual void startWork() = 0;
+ virtual void stopWork() = 0;
+ virtual void setDeviceSampleRate(int sampleRate) = 0;
+ virtual bool isRunning() = 0;
+ };
+
+ DeviceXTRXParams *m_deviceParams; //!< unique hardware device parameters
+ xtrx_channel_t m_channel; //!< logical device channel number (-1 if none)
+ ThreadInterface *m_thread; //!< holds the thread address if started else 0
+ int m_ncoFrequency;
+ double m_centerFrequency;
+ uint32_t m_log2Soft;
+ bool m_threadWasRunning; //!< flag to know if thread needs to be resumed after suspend
+
+ double m_inputRate;
+ double m_outputRate;
+ double m_masterRate;
+
+ static const float m_sampleFifoLengthInSeconds;
+ static const int m_sampleFifoMinSize;
+
+ DeviceXTRXShared() :
+ m_deviceParams(0),
+ m_channel(XTRX_CH_AB),
+ m_thread(0),
+ m_ncoFrequency(0),
+ m_centerFrequency(0),
+ m_log2Soft(0),
+ m_threadWasRunning(false),
+ m_inputRate(0),
+ m_outputRate(0),
+ m_masterRate(0)
+ {}
+
+ ~DeviceXTRXShared()
+ {}
+
+ double set_samplerate(double rate, double master, bool output);
+
+ double get_temperature();
+};
+
+#endif /* DEVICES_LIMESDR_DEVICELIMESDRSHARED_H_ */
diff --git a/plugins/samplesource/CMakeLists.txt b/plugins/samplesource/CMakeLists.txt
index 1fbdd8aa9..ca93c0c19 100644
--- a/plugins/samplesource/CMakeLists.txt
+++ b/plugins/samplesource/CMakeLists.txt
@@ -54,6 +54,11 @@ if(LIBUSB_FOUND AND RX_SAMPLE_24BIT AND LIBPERSEUS_FOUND)
add_subdirectory(perseus)
endif(LIBUSB_FOUND AND RX_SAMPLE_24BIT AND LIBPERSEUS_FOUND)
+find_package(LibXTRX)
+if(LIBXTRX_FOUND)
+ add_subdirectory(xtrxinput)
+endif(LIBXTRX_FOUND)
+
find_package(LibIIO)
if(LIBUSB_FOUND AND LIBIIO_FOUND)
add_subdirectory(plutosdrinput)
@@ -97,6 +102,7 @@ if (BUILD_DEBIAN)
add_subdirectory(rtlsdr)
add_subdirectory(sdrdaemonsource)
add_subdirectory(sdrplay)
+ add_subdirectory(xtrxinput)
add_subdirectory(soapysdrinput)
endif (BUILD_DEBIAN)
diff --git a/plugins/samplesource/xtrxinput/CMakeLists.txt b/plugins/samplesource/xtrxinput/CMakeLists.txt
new file mode 100644
index 000000000..c7cbbdd45
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/CMakeLists.txt
@@ -0,0 +1,55 @@
+project(xtrxinput)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+set(xtrxinput_SOURCES
+ xtrxinputgui.cpp
+ xtrxinput.cpp
+ xtrxinputplugin.cpp
+ xtrxinputsettings.cpp
+ xtrxinputthread.cpp
+)
+
+set(xtrxinput_HEADERS
+ xtrxinputgui.h
+ xtrxinput.h
+ xtrxinputplugin.h
+ xtrxinputsettings.h
+ xtrxinputthread.h
+)
+
+set(xtrxinput_FORMS
+ xtrxinputgui.ui
+)
+
+include_directories(
+ .
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/devices
+ ${LIBXTRX_INCLUDE_DIRS}
+)
+
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_PLUGIN)
+add_definitions(-DQT_SHARED)
+
+qt5_wrap_ui(xtrxinput_FORMS_HEADERS ${xtrxinput_FORMS})
+
+add_library(inputxtrx SHARED
+ ${xtrxinput_SOURCES}
+ ${xtrxinput_HEADERS_MOC}
+ ${xtrxinput_FORMS_HEADERS}
+)
+
+
+target_link_libraries(inputxtrx
+ ${QT_LIBRARIES}
+ ${LIBXTRX_LIBRARIES}
+ sdrbase
+ sdrgui
+ xtrxdevice
+)
+
+qt5_use_modules(inputxtrx Core Widgets)
+
+install(TARGETS inputxtrx DESTINATION lib/plugins/samplesource)
\ No newline at end of file
diff --git a/plugins/samplesource/xtrxinput/xtrxinput.cpp b/plugins/samplesource/xtrxinput/xtrxinput.cpp
new file mode 100644
index 000000000..26be437c6
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinput.cpp
@@ -0,0 +1,1136 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB //
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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
+#include "xtrx_api.h"
+
+#include "device/devicesourceapi.h"
+#include "device/devicesinkapi.h"
+#include "dsp/dspcommands.h"
+#include "dsp/filerecord.h"
+#include "xtrxinput.h"
+#include "xtrxinputthread.h"
+#include "xtrx/devicextrxparam.h"
+#include "xtrx/devicextrxshared.h"
+
+MESSAGE_CLASS_DEFINITION(XTRXInput::MsgConfigureXTRX, Message)
+MESSAGE_CLASS_DEFINITION(XTRXInput::MsgGetStreamInfo, Message)
+MESSAGE_CLASS_DEFINITION(XTRXInput::MsgGetDeviceInfo, Message)
+MESSAGE_CLASS_DEFINITION(XTRXInput::MsgReportStreamInfo, Message)
+MESSAGE_CLASS_DEFINITION(XTRXInput::MsgFileRecord, Message)
+MESSAGE_CLASS_DEFINITION(XTRXInput::MsgStartStop, Message)
+
+XTRXInput::XTRXInput(DeviceSourceAPI *deviceAPI) :
+ m_deviceAPI(deviceAPI),
+ m_settings(),
+ m_XTRXInputThread(0),
+ m_deviceDescription("XTRXInput"),
+ m_running(false),
+ m_channelAcquired(false)
+{
+
+ suspendRxBuddies();
+ suspendTxBuddies();
+ openDevice();
+ resumeTxBuddies();
+ resumeRxBuddies();
+
+ m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
+ m_deviceAPI->addSink(m_fileSink);
+}
+
+XTRXInput::~XTRXInput()
+{
+ if (m_running) stop();
+ m_deviceAPI->removeSink(m_fileSink);
+ delete m_fileSink;
+ suspendRxBuddies();
+ suspendTxBuddies();
+ closeDevice();
+ resumeTxBuddies();
+ resumeRxBuddies();
+}
+
+void XTRXInput::destroy()
+{
+ delete this;
+}
+
+bool XTRXInput::openDevice()
+{
+ if (!m_sampleFifo.setSize(96000 * 4))
+ {
+ qCritical("XTRXInput::openDevice: could not allocate SampleFifo");
+ return false;
+ }
+ else
+ {
+ qDebug("XTRXInput::openDevice: allocated SampleFifo");
+ }
+
+ xtrx_channel_t requestedChannel = m_deviceAPI->getItemIndex() ? XTRX_CH_B : XTRX_CH_A;
+
+ // look for Rx buddies and get reference to common parameters
+ // if there is a channel left take the first available
+ if (m_deviceAPI->getSourceBuddies().size() > 0) // look source sibling first
+ {
+ qDebug("XTRXInput::openDevice: look in Rx buddies");
+
+ DeviceSourceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0];
+ m_deviceShared = *((DeviceXTRXShared *) sourceBuddy->getBuddySharedPtr()); // copy shared data
+ DeviceXTRXParams *deviceParams = m_deviceShared.m_deviceParams; // get device parameters
+
+ if (deviceParams == 0)
+ {
+ qCritical("XTRXInput::openDevice: cannot get device parameters from Rx buddy");
+ return false; // the device params should have been created by the buddy
+ }
+ else
+ {
+ qDebug("XTRXInput::openDevice: getting device parameters from Rx buddy");
+ }
+
+ if (m_deviceAPI->getSourceBuddies().size() == deviceParams->m_nbRxChannels)
+ {
+ qCritical("XTRXInput::openDevice: no more Rx channels available in device");
+ return false; // no more Rx channels available in device
+ }
+ else
+ {
+ qDebug("XTRXInput::openDevice: at least one more Rx channel is available in device");
+ }
+
+ // check if the requested channel is busy and abort if so (should not happen if device management is working correctly)
+
+ char *busyChannels = new char[deviceParams->m_nbRxChannels];
+ memset(busyChannels, 0, deviceParams->m_nbRxChannels);
+
+ for (unsigned int i = 0; i < m_deviceAPI->getSourceBuddies().size(); i++)
+ {
+ DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[i];
+ DeviceXTRXShared *buddyShared = (DeviceXTRXShared *) buddy->getBuddySharedPtr();
+
+ if (buddyShared->m_channel == requestedChannel)
+ {
+ qCritical("XTRXInput::openDevice: cannot open busy channel %u", requestedChannel);
+ return false;
+ }
+ }
+
+ m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel
+ delete[] busyChannels;
+ }
+ // look for Tx buddies and get reference to common parameters
+ // take the first Rx channel
+ else if (m_deviceAPI->getSinkBuddies().size() > 0) // then sink
+ {
+ qDebug("XTRXInput::openDevice: look in Tx buddies");
+
+ DeviceSinkAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0];
+ m_deviceShared = *((DeviceXTRXShared *) sinkBuddy->getBuddySharedPtr()); // copy parameters
+
+ if (m_deviceShared.m_deviceParams == 0)
+ {
+ qCritical("XTRXInput::openDevice: cannot get device parameters from Tx buddy");
+ return false; // the device params should have been created by the buddy
+ }
+ else
+ {
+ qDebug("XTRXInput::openDevice: getting device parameters from Tx buddy");
+ }
+
+ m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel
+ }
+ // There are no buddies then create the first XTRX common parameters
+ // open the device this will also populate common fields
+ // take the first Rx channel
+ else
+ {
+ qDebug("XTRXInput::openDevice: open device here");
+
+ m_deviceShared.m_deviceParams = new DeviceXTRXParams();
+ char serial[256];
+ strcpy(serial, qPrintable(m_deviceAPI->getSampleSourceSerial()));
+
+ if (!m_deviceShared.m_deviceParams->open(serial)) {
+ delete m_deviceShared.m_deviceParams;
+ m_deviceShared.m_deviceParams = 0;
+
+ return false;
+ }
+
+ m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel
+ }
+
+ m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API
+
+ return true;
+}
+
+void XTRXInput::suspendRxBuddies()
+{
+ const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies();
+ std::vector::const_iterator itSource = sourceBuddies.begin();
+
+ qDebug("XTRXInput::suspendRxBuddies (%lu)", sourceBuddies.size());
+
+ for (; itSource != sourceBuddies.end(); ++itSource)
+ {
+ DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSource)->getBuddySharedPtr();
+
+ if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning())
+ {
+ buddySharedPtr->m_thread->stopWork();
+ buddySharedPtr->m_threadWasRunning = true;
+ }
+ else
+ {
+ buddySharedPtr->m_threadWasRunning = false;
+ }
+ }
+}
+
+void XTRXInput::suspendTxBuddies()
+{
+ const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies();
+ std::vector::const_iterator itSink = sinkBuddies.begin();
+
+ qDebug("XTRXInput::suspendTxBuddies (%lu)", sinkBuddies.size());
+
+ for (; itSink != sinkBuddies.end(); ++itSink)
+ {
+ DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSink)->getBuddySharedPtr();
+
+ if (buddySharedPtr->m_thread) {
+ buddySharedPtr->m_thread->stopWork();
+ buddySharedPtr->m_threadWasRunning = true;
+ }
+ else
+ {
+ buddySharedPtr->m_threadWasRunning = false;
+ }
+ }
+}
+
+void XTRXInput::resumeRxBuddies()
+{
+ const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies();
+ std::vector::const_iterator itSource = sourceBuddies.begin();
+
+ qDebug("XTRXInput::resumeRxBuddies (%lu)", sourceBuddies.size());
+
+ for (; itSource != sourceBuddies.end(); ++itSource)
+ {
+ DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSource)->getBuddySharedPtr();
+
+ if (buddySharedPtr->m_threadWasRunning) {
+ buddySharedPtr->m_thread->startWork();
+ }
+ }
+}
+
+void XTRXInput::resumeTxBuddies()
+{
+ const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies();
+ std::vector::const_iterator itSink = sinkBuddies.begin();
+
+ qDebug("XTRXInput::resumeTxBuddies (%lu)", sinkBuddies.size());
+
+ for (; itSink != sinkBuddies.end(); ++itSink)
+ {
+ DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSink)->getBuddySharedPtr();
+
+ if (buddySharedPtr->m_threadWasRunning) {
+ buddySharedPtr->m_thread->startWork();
+ }
+ }
+}
+
+void XTRXInput::closeDevice()
+{
+ if (m_deviceShared.m_deviceParams->getDevice() == 0) { // was never open
+ return;
+ }
+
+ if (m_running) { stop(); }
+
+ m_deviceShared.m_channel = XTRX_CH_AB;
+
+ // No buddies so effectively close the device
+
+ if ((m_deviceAPI->getSinkBuddies().size() == 0) && (m_deviceAPI->getSourceBuddies().size() == 0))
+ {
+ m_deviceShared.m_deviceParams->close();
+ delete m_deviceShared.m_deviceParams;
+ m_deviceShared.m_deviceParams = 0;
+ }
+}
+
+bool XTRXInput::acquireChannel()
+{
+ //suspendRxBuddies();
+ //suspendTxBuddies();
+
+ qDebug("XTRXInput::acquireChannel: stream set up on Rx channel %d", m_deviceShared.m_channel);
+
+ //resumeTxBuddies();
+ //resumeRxBuddies();
+
+ m_channelAcquired = true;
+ return true;
+}
+
+void XTRXInput::releaseChannel()
+{
+ //suspendRxBuddies();
+ //suspendTxBuddies();
+
+ qDebug("XTRXInput::releaseChannel: Rx channel %d disabled", m_deviceShared.m_channel);
+
+ //resumeTxBuddies();
+ //resumeRxBuddies();
+
+ // The channel will be effectively released to be reused in another device set only at close time
+
+ m_channelAcquired = false;
+}
+
+void XTRXInput::init()
+{
+ applySettings(m_settings, true, false);
+}
+
+bool XTRXInput::start()
+{
+ if (!m_deviceShared.m_deviceParams->getDevice()) {
+ return false;
+ }
+
+ if (m_running) { stop(); }
+
+ if (!acquireChannel())
+ {
+ return false;
+ }
+
+ applySettings(m_settings, true);
+
+ // start / stop streaming is done in the thread.
+
+ if ((m_XTRXInputThread = new XTRXInputThread(&m_deviceShared, &m_sampleFifo)) == 0)
+ {
+ qFatal("XTRXInput::start: cannot create thread");
+ stop();
+ return false;
+ }
+ else
+ {
+ qDebug("XTRXInput::start: thread created");
+ }
+
+ m_XTRXInputThread->setLog2Decimation(m_settings.m_log2SoftDecim);
+
+ m_XTRXInputThread->startWork();
+
+ m_deviceShared.m_thread = m_XTRXInputThread;
+ m_running = true;
+
+ return true;
+}
+
+void XTRXInput::stop()
+{
+ qDebug("XTRXInput::stop");
+
+ if (m_XTRXInputThread != 0)
+ {
+ m_XTRXInputThread->stopWork();
+ delete m_XTRXInputThread;
+ m_XTRXInputThread = 0;
+ }
+
+ m_deviceShared.m_thread = 0;
+ m_running = false;
+
+ releaseChannel();
+}
+
+QByteArray XTRXInput::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool XTRXInput::deserialize(const QByteArray& data)
+{
+ bool success = true;
+
+ if (!m_settings.deserialize(data))
+ {
+ m_settings.resetToDefaults();
+ success = false;
+ }
+
+ MsgConfigureXTRX* message = MsgConfigureXTRX::create(m_settings, true);
+ m_inputMessageQueue.push(message);
+
+ if (m_guiMessageQueue)
+ {
+ MsgConfigureXTRX* messageToGUI = MsgConfigureXTRX::create(m_settings, true);
+ m_guiMessageQueue->push(messageToGUI);
+ }
+
+ return success;
+}
+
+const QString& XTRXInput::getDeviceDescription() const
+{
+ return m_deviceDescription;
+}
+
+int XTRXInput::getSampleRate() const
+{
+ double rate = m_settings.m_devSampleRate;
+ return (int)((rate / (1<push(messageToGUI);
+ }
+}
+
+std::size_t XTRXInput::getChannelIndex()
+{
+ return m_deviceShared.m_channel;
+}
+
+void XTRXInput::getLORange(float& minF, float& maxF, float& stepF) const
+{
+ minF = 29e6;
+ maxF = 3840e6;
+ stepF = 10;
+ qDebug("XTRXInput::getLORange: min: %f max: %f step: %f",
+ minF, maxF, stepF);
+}
+
+void XTRXInput::getSRRange(float& minF, float& maxF, float& stepF) const
+{
+ minF = 100e3;
+ maxF = 120e6;
+ stepF = 10;
+ qDebug("XTRXInput::getSRRange: min: %f max: %f step: %f",
+ minF, maxF, stepF);
+}
+
+void XTRXInput::getLPRange(float& minF, float& maxF, float& stepF) const
+{
+ minF = 500e3;
+ maxF = 130e6;
+ stepF = 10;
+ qDebug("XTRXInput::getLPRange: min: %f max: %f step: %f",
+ minF, maxF, stepF);
+}
+
+uint32_t XTRXInput::getHWLog2Decim() const
+{
+ return m_deviceShared.m_deviceParams->m_log2OvSRRx;
+}
+
+bool XTRXInput::handleMessage(const Message& message)
+{
+ if (MsgConfigureXTRX::match(message))
+ {
+ MsgConfigureXTRX& conf = (MsgConfigureXTRX&) message;
+ qDebug() << "XTRXInput::handleMessage: MsgConfigureXTRX";
+
+ if (!applySettings(conf.getSettings(), conf.getForce()))
+ {
+ qDebug("XTRXInput::handleMessage config error");
+ }
+
+ return true;
+ }
+ else if (DeviceXTRXShared::MsgReportBuddyChange::match(message))
+ {
+ DeviceXTRXShared::MsgReportBuddyChange& report = (DeviceXTRXShared::MsgReportBuddyChange&) message;
+
+ if (report.getRxElseTx())
+ {
+ m_settings.m_devSampleRate = report.getDevSampleRate();
+ m_settings.m_log2HardDecim = report.getLog2HardDecimInterp();
+ m_settings.m_centerFrequency = report.getCenterFrequency();
+ }
+ else
+ {
+ m_settings.m_devSampleRate = m_deviceShared.m_inputRate;
+ m_settings.m_log2HardDecim = log2(m_deviceShared.m_masterRate / m_deviceShared.m_inputRate / 4);
+
+ qDebug() << "XTRXInput::handleMessage: MsgReportBuddyChange:"
+ << " host_Hz: " << m_deviceShared.m_inputRate
+ << " rf_Hz: " << m_deviceShared.m_masterRate / 4
+ << " m_log2HardDecim: " << m_settings.m_log2HardDecim;
+ }
+
+ if (m_settings.m_ncoEnable) // need to reset NCO after sample rate change
+ {
+ applySettings(m_settings, true, true);
+ }
+
+ int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
+
+ DSPSignalNotification *notif = new DSPSignalNotification(
+ m_settings.m_devSampleRate/(1<getDeviceEngineInputMessageQueue()->push(notif);
+
+ DeviceXTRXShared::MsgReportBuddyChange *reportToGUI = DeviceXTRXShared::MsgReportBuddyChange::create(
+ m_settings.m_devSampleRate, m_settings.m_log2HardDecim, m_settings.m_centerFrequency, true);
+ getMessageQueueToGUI()->push(reportToGUI);
+
+ return true;
+ }
+ else if (DeviceXTRXShared::MsgReportClockSourceChange::match(message))
+ {
+ DeviceXTRXShared::MsgReportClockSourceChange& report = (DeviceXTRXShared::MsgReportClockSourceChange&) message;
+
+ m_settings.m_extClock = report.getExtClock();
+ m_settings.m_extClockFreq = report.getExtClockFeq();
+
+ DeviceXTRXShared::MsgReportClockSourceChange *reportToGUI = DeviceXTRXShared::MsgReportClockSourceChange::create(
+ m_settings.m_extClock, m_settings.m_extClockFreq);
+ getMessageQueueToGUI()->push(reportToGUI);
+
+ return true;
+ }
+ else if (MsgGetStreamInfo::match(message))
+ {
+ qDebug() << "XTRXInput::handleMessage: MsgGetStreamInfo";
+
+ if (m_deviceAPI->getSampleSourceGUIMessageQueue())
+ {
+ uint64_t fifolevel;
+
+ xtrx_val_get(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_RX, XTRX_CH_AB, XTRX_PERF_LLFIFO, &fifolevel);
+
+ MsgReportStreamInfo *report = MsgReportStreamInfo::create(
+ true,
+ true,
+ fifolevel,
+ 65536,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0);
+ m_deviceAPI->getSampleSourceGUIMessageQueue()->push(report);
+ }
+ return true;
+ }
+ else if (MsgGetDeviceInfo::match(message))
+ {
+ double temp = 0.0;
+ if (m_deviceShared.m_deviceParams->getDevice() && (
+ (temp = m_deviceShared.get_temperature() / 256.0) != 0.0))
+ {
+ qDebug("XTRXInput::handleMessage: MsgGetDeviceInfo: temperature: %f", temp);
+ }
+ else
+ {
+ qDebug("XTRXInput::handleMessage: MsgGetDeviceInfo: cannot get temperature");
+ }
+
+ // send to oneself
+ if (m_deviceAPI->getSampleSourceGUIMessageQueue()) {
+ DeviceXTRXShared::MsgReportDeviceInfo *report = DeviceXTRXShared::MsgReportDeviceInfo::create(temp);
+ m_deviceAPI->getSampleSourceGUIMessageQueue()->push(report);
+ }
+
+ // send to source buddies
+ const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies();
+ std::vector::const_iterator itSource = sourceBuddies.begin();
+
+ for (; itSource != sourceBuddies.end(); ++itSource)
+ {
+ if ((*itSource)->getSampleSourceGUIMessageQueue())
+ {
+ DeviceXTRXShared::MsgReportDeviceInfo *report = DeviceXTRXShared::MsgReportDeviceInfo::create(temp);
+ (*itSource)->getSampleSourceGUIMessageQueue()->push(report);
+ }
+ }
+
+ // send to sink buddies
+ const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies();
+ std::vector::const_iterator itSink = sinkBuddies.begin();
+
+ for (; itSink != sinkBuddies.end(); ++itSink)
+ {
+ if ((*itSink)->getSampleSinkGUIMessageQueue())
+ {
+ DeviceXTRXShared::MsgReportDeviceInfo *report = DeviceXTRXShared::MsgReportDeviceInfo::create(temp);
+ (*itSink)->getSampleSinkGUIMessageQueue()->push(report);
+ }
+ }
+
+ return true;
+ }
+ else if (MsgFileRecord::match(message))
+ {
+ MsgFileRecord& conf = (MsgFileRecord&) message;
+ qDebug() << "XTRXInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
+
+ if (conf.getStartStop()) {
+ m_fileSink->startRecording();
+ } else {
+ m_fileSink->stopRecording();
+ }
+
+ return true;
+ }
+ else if (MsgStartStop::match(message))
+ {
+ MsgStartStop& cmd = (MsgStartStop&) message;
+ qDebug() << "XTRXInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
+
+ if (cmd.getStartStop())
+ {
+ if (m_deviceAPI->initAcquisition())
+ {
+ m_deviceAPI->startAcquisition();
+ }
+ }
+ else
+ {
+ m_deviceAPI->stopAcquisition();
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+static double tia_to_db(unsigned idx)
+{
+ switch (idx) {
+ case 1: return 12;
+ case 2: return 9;
+ default: return 0;
+ }
+}
+
+void XTRXInput::apply_gain_auto(double gain)
+{
+ if (xtrx_set_gain(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_CH_AB /*m_deviceShared.m_channel*/,
+ XTRX_RX_LNA_GAIN,
+ gain,
+ NULL) < 0)
+ {
+ qDebug("XTRXInput::applySettings: xtrx_set_gain(auto) failed");
+ }
+ else
+ {
+ //doCalibration = true;
+ qDebug() << "XTRXInput::applySettings: Gain (auto) set to " << gain;
+ }
+}
+
+void XTRXInput::apply_gain_lna(double gain)
+{
+ if (xtrx_set_gain(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_CH_AB /*m_deviceShared.m_channel*/,
+ XTRX_RX_LNA_GAIN,
+ gain,
+ NULL) < 0)
+ {
+ qDebug("XTRXInput::applySettings: xtrx_set_gain(LNA) failed");
+ }
+ else
+ {
+ qDebug() << "XTRXInput::applySettings: Gain (LNA) set to " << gain;
+ }
+}
+
+void XTRXInput::apply_gain_tia(double gain)
+{
+ if (xtrx_set_gain(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_CH_AB /*m_deviceShared.m_channel*/,
+ XTRX_RX_TIA_GAIN,
+ gain,
+ NULL) < 0)
+ {
+ qDebug("XTRXInput::applySettings: xtrx_set_gain(TIA) failed");
+ }
+ else
+ {
+ qDebug() << "XTRXInput::applySettings: Gain (TIA) set to " << gain;
+ }
+}
+
+void XTRXInput::apply_gain_pga(double gain)
+{
+ if (xtrx_set_gain(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_CH_AB /*m_deviceShared.m_channel*/,
+ XTRX_RX_TIA_GAIN,
+ gain,
+ NULL) < 0)
+ {
+ qDebug("XTRXInput::applySettings: xtrx_set_gain(PGA) failed");
+ }
+ else
+ {
+ qDebug() << "XTRXInput::applySettings: Gain (PGA) set to " << gain;
+ }
+}
+
+bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, bool forceNCOFrequency)
+{
+ bool forwardChangeOwnDSP = false;
+ bool forwardChangeRxDSP = false;
+ bool forwardChangeAllDSP = false;
+ bool forwardClockSource = false;
+ bool ownThreadWasRunning = false;
+ bool doLPCalibration = false;
+ bool doChangeSampleRate = false;
+ bool doChangeFreq = false;
+
+ bool doGainAuto = false;
+ bool doGainLna = false;
+ bool doGainTia = false;
+ bool doGainPga = false;
+
+ // apply settings
+
+ if ((m_settings.m_dcBlock != settings.m_dcBlock) || force)
+ {
+ m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection);
+ }
+
+ if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
+ {
+ m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection);
+ }
+
+ if ((m_settings.m_pwrmode != settings.m_pwrmode)) {
+ if (xtrx_val_set(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_TRX, XTRX_CH_AB, XTRX_LMS7_PWR_MODE, settings.m_pwrmode) < 0)
+ {
+ qCritical("XTRXInput::applySettings: could not set power mode %d",
+ settings.m_pwrmode);
+ }
+ }
+
+ if ((m_settings.m_extClock != settings.m_extClock) ||
+ (settings.m_extClock && (m_settings.m_extClockFreq != settings.m_extClockFreq)) || force)
+ {
+
+ xtrx_set_ref_clk(m_deviceShared.m_deviceParams->getDevice(),
+ (settings.m_extClock) ? settings.m_extClockFreq : 0,
+ (settings.m_extClock) ? XTRX_CLKSRC_EXT : XTRX_CLKSRC_INT);
+ {
+ forwardClockSource = true;
+ doChangeSampleRate = true;
+ doChangeFreq = true;
+ qDebug("XTRXInput::applySettings: clock set to %s (Ext: %d Hz)",
+ settings.m_extClock ? "external" : "internal",
+ settings.m_extClockFreq);
+ }
+ }
+
+ if ((m_settings.m_devSampleRate != settings.m_devSampleRate)
+ || (m_settings.m_log2HardDecim != settings.m_log2HardDecim) || force)
+ {
+ forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate;
+
+ if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired)
+ {
+ doChangeSampleRate = true;
+ }
+ }
+
+ if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired)
+ {
+ if ((m_settings.m_gainMode != settings.m_gainMode) || force)
+ {
+ if (settings.m_gainMode == XTRXInputSettings::GAIN_AUTO)
+ {
+ doGainAuto = true;
+ }
+ else
+ {
+ doGainLna = true;
+ doGainTia = true;
+ doGainPga = true;
+ }
+ }
+ else if (m_settings.m_gainMode == XTRXInputSettings::GAIN_AUTO)
+ {
+ doGainAuto = true;
+ }
+ else if (m_settings.m_gainMode == XTRXInputSettings::GAIN_MANUAL)
+ {
+ if (m_settings.m_lnaGain != settings.m_lnaGain)
+ {
+ doGainLna = true;
+ }
+ if (m_settings.m_tiaGain != settings.m_tiaGain)
+ {
+ doGainTia = true;
+ }
+ if (m_settings.m_pgaGain != settings.m_pgaGain)
+ {
+ doGainPga = true;
+ }
+ }
+ }
+
+ if ((m_settings.m_lpfBW != settings.m_lpfBW) || force)
+ {
+ if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired)
+ {
+ doLPCalibration = true;
+ }
+ }
+
+#if 0
+ if ((m_settings.m_lpfFIRBW != settings.m_lpfFIRBW) ||
+ (m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) || force)
+ {
+ if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired)
+ {
+ if (LMS_SetGFIRLPF(m_deviceShared.m_deviceParams->getDevice(),
+ LMS_CH_RX,
+ m_deviceShared.m_channel,
+ settings.m_lpfFIREnable,
+ settings.m_lpfFIRBW) < 0)
+ {
+ qCritical("XTRXInput::applySettings: could %s and set LPF FIR to %f Hz",
+ settings.m_lpfFIREnable ? "enable" : "disable",
+ settings.m_lpfFIRBW);
+ }
+ else
+ {
+ //doCalibration = true;
+ qDebug("XTRXInput::applySettings: %sd and set LPF FIR to %f Hz",
+ settings.m_lpfFIREnable ? "enable" : "disable",
+ settings.m_lpfFIRBW);
+ }
+ }
+ }
+#endif
+
+
+ if ((m_settings.m_log2SoftDecim != settings.m_log2SoftDecim) || force)
+ {
+ forwardChangeOwnDSP = true;
+ m_deviceShared.m_log2Soft = settings.m_log2SoftDecim; // for buddies
+
+ if (m_XTRXInputThread != 0)
+ {
+ m_XTRXInputThread->setLog2Decimation(settings.m_log2SoftDecim);
+ qDebug() << "XTRXInput::applySettings: set soft decimation to " << (1<getDevice() != 0 && m_channelAcquired)
+ {
+ if (xtrx_set_antenna(m_deviceShared.m_deviceParams->getDevice(),
+ settings.m_antennaPath) < 0)
+ {
+ qCritical("XTRXInput::applySettings: could not set antenna path to %d",
+ (int) settings.m_antennaPath);
+ }
+ else
+ {
+ qDebug("XTRXInput::applySettings: set antenna path to %d on channel %d",
+ (int) settings.m_antennaPath,
+ m_deviceShared.m_channel);
+ }
+ }
+ }
+
+ if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force)
+ {
+ doChangeFreq = true;
+ }
+
+ if ((m_settings.m_ncoFrequency != settings.m_ncoFrequency) ||
+ (m_settings.m_ncoEnable != settings.m_ncoEnable) || force)
+ {
+ forceNCOFrequency = true;
+ }
+
+
+ m_settings = settings;
+
+ if (doChangeSampleRate)
+ {
+ if (m_XTRXInputThread && m_XTRXInputThread->isRunning())
+ {
+ m_XTRXInputThread->stopWork();
+ ownThreadWasRunning = true;
+ }
+
+ suspendRxBuddies();
+ suspendTxBuddies();
+
+ double master = (settings.m_log2HardDecim == 0) ? 0 : (settings.m_devSampleRate * 4 * (1 << settings.m_log2HardDecim));
+ if (m_deviceShared.set_samplerate(settings.m_devSampleRate,
+ master, //(settings.m_devSampleRate<m_log2OvSRRx = settings.m_log2HardDecim;
+ m_deviceShared.m_deviceParams->m_sampleRate = settings.m_devSampleRate;
+
+ doChangeFreq = true;
+ forceNCOFrequency = true;
+ qDebug("XTRXInput::applySettings: set sample rate set to %f with oversampling of %d",
+ settings.m_devSampleRate,
+ 1<startWork();
+ }
+ }
+
+ if (doLPCalibration)
+ {
+ if (xtrx_tune_rx_bandwidth(m_deviceShared.m_deviceParams->getDevice(),
+ m_deviceShared.m_channel,
+ m_settings.m_lpfBW,
+ NULL) < 0)
+ {
+ qCritical("XTRXInput::applySettings: could not set LPF to %f Hz", m_settings.m_lpfBW);
+ }
+ else
+ {
+ qDebug("XTRXInput::applySettings: LPF set to %f Hz", m_settings.m_lpfBW);
+ }
+ }
+
+ if (doGainAuto)
+ {
+ apply_gain_auto(m_settings.m_gain);
+ }
+ if (doGainLna)
+ {
+ apply_gain_auto(m_settings.m_lnaGain);
+ }
+ if (doGainTia)
+ {
+ apply_gain_auto(tia_to_db(m_settings.m_tiaGain));
+ }
+ if (doGainPga)
+ {
+ apply_gain_auto(m_settings.m_pgaGain);
+ }
+
+ if (doChangeFreq)
+ {
+ forwardChangeRxDSP = true;
+
+ if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired)
+ {
+ if (xtrx_tune(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_TUNE_RX_FDD,
+ settings.m_centerFrequency,
+ NULL) < 0)
+ {
+ qCritical("XTRXInput::applySettings: could not set frequency to %lu", settings.m_centerFrequency);
+ }
+ else
+ {
+ //doCalibration = true;
+ m_deviceShared.m_centerFrequency = settings.m_centerFrequency; // for buddies
+ qDebug("XTRXInput::applySettings: frequency set to %lu", settings.m_centerFrequency);
+ }
+ }
+ }
+
+ if (forceNCOFrequency)
+ {
+ if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired)
+ {
+ if (xtrx_tune(m_deviceShared.m_deviceParams->getDevice(),
+ XTRX_TUNE_BB_RX,
+ /* m_deviceShared.m_channel, */
+ (settings.m_ncoEnable) ? settings.m_ncoFrequency : 0,
+ NULL) < 0)
+ {
+ qCritical("XTRXInput::applySettings: could not %s and set NCO to %d Hz",
+ settings.m_ncoEnable ? "enable" : "disable",
+ settings.m_ncoFrequency);
+ }
+ else
+ {
+ forwardChangeOwnDSP = true;
+ m_deviceShared.m_ncoFrequency = settings.m_ncoEnable ? settings.m_ncoFrequency : 0; // for buddies
+ qDebug("XTRXInput::applySettings: %sd and set NCO to %d Hz",
+ settings.m_ncoEnable ? "enable" : "disable",
+ settings.m_ncoFrequency);
+ }
+ }
+ }
+
+
+ // forward changes to buddies or oneself
+
+ if (forwardChangeAllDSP)
+ {
+ qDebug("XTRXInput::applySettings: forward change to all buddies");
+
+ int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
+
+ // send to self first
+ DSPSignalNotification *notif = new DSPSignalNotification(
+ m_settings.m_devSampleRate/(1<getDeviceEngineInputMessageQueue()->push(notif);
+
+ // send to source buddies
+ const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies();
+ std::vector::const_iterator itSource = sourceBuddies.begin();
+
+ for (; itSource != sourceBuddies.end(); ++itSource)
+ {
+ DeviceXTRXShared::MsgReportBuddyChange *report = DeviceXTRXShared::MsgReportBuddyChange::create(
+ m_settings.m_devSampleRate, m_settings.m_log2HardDecim, m_settings.m_centerFrequency, true);
+ (*itSource)->getSampleSourceInputMessageQueue()->push(report);
+ }
+
+ // send to sink buddies
+ const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies();
+ std::vector::const_iterator itSink = sinkBuddies.begin();
+
+ for (; itSink != sinkBuddies.end(); ++itSink)
+ {
+ DeviceXTRXShared::MsgReportBuddyChange *report = DeviceXTRXShared::MsgReportBuddyChange::create(
+ m_settings.m_devSampleRate, m_settings.m_log2HardDecim, m_settings.m_centerFrequency, true);
+ (*itSink)->getSampleSinkInputMessageQueue()->push(report);
+ }
+ }
+ else if (forwardChangeRxDSP)
+ {
+ qDebug("XTRXInput::applySettings: forward change to Rx buddies");
+
+ int sampleRate = m_settings.m_devSampleRate/(1<getDeviceEngineInputMessageQueue()->push(notif);
+
+ // send to source buddies
+ const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies();
+ std::vector::const_iterator itSource = sourceBuddies.begin();
+
+ for (; itSource != sourceBuddies.end(); ++itSource)
+ {
+ DeviceXTRXShared::MsgReportBuddyChange *report = DeviceXTRXShared::MsgReportBuddyChange::create(
+ m_settings.m_devSampleRate, m_settings.m_log2HardDecim, m_settings.m_centerFrequency, true);
+ (*itSource)->getSampleSourceInputMessageQueue()->push(report);
+ }
+ }
+ else if (forwardChangeOwnDSP)
+ {
+ qDebug("XTRXInput::applySettings: forward change to self only");
+
+ int sampleRate = m_settings.m_devSampleRate/(1<handleMessage(*notif); // forward to file sink
+ m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
+ }
+
+ if (forwardClockSource)
+ {
+ // send to source buddies
+ const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies();
+ std::vector::const_iterator itSource = sourceBuddies.begin();
+
+ for (; itSource != sourceBuddies.end(); ++itSource)
+ {
+ DeviceXTRXShared::MsgReportClockSourceChange *report = DeviceXTRXShared::MsgReportClockSourceChange::create(
+ m_settings.m_extClock, m_settings.m_extClockFreq);
+ (*itSource)->getSampleSourceInputMessageQueue()->push(report);
+ }
+
+ // send to sink buddies
+ const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies();
+ std::vector::const_iterator itSink = sinkBuddies.begin();
+
+ for (; itSink != sinkBuddies.end(); ++itSink)
+ {
+ DeviceXTRXShared::MsgReportClockSourceChange *report = DeviceXTRXShared::MsgReportClockSourceChange::create(
+ m_settings.m_extClock, m_settings.m_extClockFreq);
+ (*itSink)->getSampleSinkInputMessageQueue()->push(report);
+ }
+ }
+
+ qDebug() << "XTRXInput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
+ << " device stream sample rate: " << m_settings.m_devSampleRate << "S/s"
+ << " sample rate with soft decimation: " << m_settings.m_devSampleRate/(1<. //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUT_H_
+#define PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUT_H_
+
+#include
+#include
+
+#include "dsp/devicesamplesource.h"
+#include "xtrx/devicextrxshared.h"
+#include "xtrxinputsettings.h"
+
+class DeviceSourceAPI;
+class XTRXInputThread;
+struct DeviceXTRXParams;
+class FileRecord;
+
+class XTRXInput : public DeviceSampleSource
+{
+public:
+ class MsgConfigureXTRX : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const XTRXInputSettings& getSettings() const { return m_settings; }
+ bool getForce() const { return m_force; }
+
+ static MsgConfigureXTRX* create(const XTRXInputSettings& settings, bool force)
+ {
+ return new MsgConfigureXTRX(settings, force);
+ }
+
+ private:
+ XTRXInputSettings m_settings;
+ bool m_force;
+
+ MsgConfigureXTRX(const XTRXInputSettings& settings, bool force) :
+ Message(),
+ m_settings(settings),
+ m_force(force)
+ { }
+ };
+
+ class MsgGetStreamInfo : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ static MsgGetStreamInfo* create()
+ {
+ return new MsgGetStreamInfo();
+ }
+
+ private:
+ MsgGetStreamInfo() :
+ Message()
+ { }
+ };
+
+ class MsgGetDeviceInfo : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ static MsgGetDeviceInfo* create()
+ {
+ return new MsgGetDeviceInfo();
+ }
+
+ private:
+ MsgGetDeviceInfo() :
+ Message()
+ { }
+ };
+
+ class MsgReportStreamInfo : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ bool getSuccess() const { return m_success; }
+ bool getActive() const { return m_active; }
+ uint32_t getFifoFilledCount() const { return m_fifoFilledCount; }
+ uint32_t getFifoSize() const { return m_fifoSize; }
+ uint32_t getUnderrun() const { return m_underrun; }
+ uint32_t getOverrun() const { return m_overrun; }
+ uint32_t getDroppedPackets() const { return m_droppedPackets; }
+ float getSampleRate() const { return m_sampleRate; }
+ float getLinkRate() const { return m_linkRate; }
+ uint64_t getTimestamp() const { return m_timestamp; }
+
+ static MsgReportStreamInfo* create(
+ bool success,
+ bool active,
+ uint32_t fifoFilledCount,
+ uint32_t fifoSize,
+ uint32_t underrun,
+ uint32_t overrun,
+ uint32_t droppedPackets,
+ float sampleRate,
+ float linkRate,
+ uint64_t timestamp
+ )
+ {
+ return new MsgReportStreamInfo(
+ success,
+ active,
+ fifoFilledCount,
+ fifoSize,
+ underrun,
+ overrun,
+ droppedPackets,
+ sampleRate,
+ linkRate,
+ timestamp
+ );
+ }
+
+ private:
+ bool m_success;
+ // everything from lms_stream_status_t
+ bool m_active; //!< Indicates whether the stream is currently active
+ uint32_t m_fifoFilledCount; //!< Number of samples in FIFO buffer
+ uint32_t m_fifoSize; //!< Size of FIFO buffer
+ uint32_t m_underrun; //!< FIFO underrun count
+ uint32_t m_overrun; //!< FIFO overrun count
+ uint32_t m_droppedPackets; //!< Number of dropped packets by HW
+ float m_sampleRate; //!< Sampling rate of the stream
+ float m_linkRate; //!< Combined data rate of all stream of the same direction (TX or RX)
+ uint64_t m_timestamp; //!< Current HW timestamp
+
+ MsgReportStreamInfo(
+ bool success,
+ bool active,
+ uint32_t fifoFilledCount,
+ uint32_t fifoSize,
+ uint32_t underrun,
+ uint32_t overrun,
+ uint32_t droppedPackets,
+ float sampleRate,
+ float linkRate,
+ uint64_t timestamp
+ ) :
+ Message(),
+ m_success(success),
+ m_active(active),
+ m_fifoFilledCount(fifoFilledCount),
+ m_fifoSize(fifoSize),
+ m_underrun(underrun),
+ m_overrun(overrun),
+ m_droppedPackets(droppedPackets),
+ m_sampleRate(sampleRate),
+ m_linkRate(linkRate),
+ m_timestamp(timestamp)
+ { }
+ };
+
+ class MsgStartStop : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ bool getStartStop() const { return m_startStop; }
+
+ static MsgStartStop* create(bool startStop) {
+ return new MsgStartStop(startStop);
+ }
+
+ protected:
+ bool m_startStop;
+
+ MsgStartStop(bool startStop) :
+ Message(),
+ m_startStop(startStop)
+ { }
+ };
+
+ class MsgFileRecord : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ bool getStartStop() const { return m_startStop; }
+
+ static MsgFileRecord* create(bool startStop) {
+ return new MsgFileRecord(startStop);
+ }
+
+ protected:
+ bool m_startStop;
+
+ MsgFileRecord(bool startStop) :
+ Message(),
+ m_startStop(startStop)
+ { }
+ };
+
+ XTRXInput(DeviceSourceAPI *deviceAPI);
+ virtual ~XTRXInput();
+ virtual void destroy();
+
+ virtual void init();
+ virtual bool start();
+ virtual void stop();
+
+ virtual QByteArray serialize() const;
+ virtual bool deserialize(const QByteArray& data);
+
+ virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
+ virtual const QString& getDeviceDescription() const;
+ virtual int getSampleRate() const;
+ virtual quint64 getCenterFrequency() const;
+ virtual void setCenterFrequency(qint64 centerFrequency);
+
+ virtual bool handleMessage(const Message& message);
+
+ std::size_t getChannelIndex();
+ void getLORange(float& minF, float& maxF, float& stepF) const;
+ void getSRRange(float& minF, float& maxF, float& stepF) const;
+ void getLPRange(float& minF, float& maxF, float& stepF) const;
+ uint32_t getHWLog2Decim() const;
+
+ void apply_gain_auto(double gain);
+ void apply_gain_lna(double gain);
+ void apply_gain_tia(double gain);
+ void apply_gain_pga(double gain);
+
+private:
+ DeviceSourceAPI *m_deviceAPI;
+ QMutex m_mutex;
+ XTRXInputSettings m_settings;
+ XTRXInputThread* m_XTRXInputThread;
+ QString m_deviceDescription;
+ bool m_running;
+ DeviceXTRXShared m_deviceShared;
+ bool m_channelAcquired;
+
+ FileRecord *m_fileSink; //!< File sink to record device I/Q output
+
+ bool openDevice();
+ void closeDevice();
+ bool acquireChannel();
+ void releaseChannel();
+ void suspendRxBuddies();
+ void resumeRxBuddies();
+ void suspendTxBuddies();
+ void resumeTxBuddies();
+ bool applySettings(const XTRXInputSettings& settings, bool force = false, bool forceNCOFrequency = false);
+};
+
+#endif /* PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUT_H_ */
diff --git a/plugins/samplesource/xtrxinput/xtrxinputgui.cpp b/plugins/samplesource/xtrxinput/xtrxinputgui.cpp
new file mode 100644
index 000000000..5b1b162f1
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputgui.cpp
@@ -0,0 +1,590 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB //
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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 "xtrxinputgui.h"
+
+#include
+#include
+
+#include
+
+#include "ui_xtrxinputgui.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"
+
+XTRXInputGUI::XTRXInputGUI(DeviceUISet *deviceUISet, QWidget* parent) :
+ QWidget(parent),
+ ui(new Ui::XTRXInputGUI),
+ m_deviceUISet(deviceUISet),
+ m_settings(),
+ m_sampleRate(0),
+ m_lastEngineState((DSPDeviceSourceEngine::State)-1),
+ m_doApplySettings(true),
+ m_forceSettings(true),
+ m_statusCounter(0),
+ m_deviceStatusCounter(0)
+{
+ m_XTRXInput = (XTRXInput*) m_deviceUISet->m_deviceSourceAPI->getSampleSource();
+
+ ui->setupUi(this);
+
+ float minF, maxF, stepF;
+
+ m_XTRXInput->getLORange(minF, maxF, stepF);
+ ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
+ ui->centerFrequency->setValueRange(7, ((uint32_t) minF)/1000, ((uint32_t) maxF)/1000); // frequency dial is in kHz
+
+ m_XTRXInput->getSRRange(minF, maxF, stepF);
+ ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
+ ui->sampleRate->setValueRange(8, (uint32_t) minF, (uint32_t) maxF);
+
+ m_XTRXInput->getLPRange(minF, maxF, stepF);
+ ui->lpf->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
+ ui->lpf->setValueRange(6, (minF/1000)+1, maxF/1000);
+
+ ui->lpFIR->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
+ ui->lpFIR->setValueRange(5, 1U, 56000U);
+
+ ui->ncoFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
+
+ ui->channelNumberText->setText(tr("#%1").arg(m_XTRXInput->getChannelIndex()));
+
+ ui->hwDecimLabel->setText(QString::fromUtf8("H\u2193"));
+ ui->swDecimLabel->setText(QString::fromUtf8("S\u2193"));
+
+ 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);
+}
+
+XTRXInputGUI::~XTRXInputGUI()
+{
+ delete ui;
+}
+
+void XTRXInputGUI::destroy()
+{
+ delete this;
+}
+
+void XTRXInputGUI::setName(const QString& name)
+{
+ setObjectName(name);
+}
+
+QString XTRXInputGUI::getName() const
+{
+ return objectName();
+}
+
+void XTRXInputGUI::resetToDefaults()
+{
+ m_settings.resetToDefaults();
+ displaySettings();
+ sendSettings();
+}
+
+qint64 XTRXInputGUI::getCenterFrequency() const
+{
+ return m_settings.m_centerFrequency;
+}
+
+void XTRXInputGUI::setCenterFrequency(qint64 centerFrequency)
+{
+ m_settings.m_centerFrequency = centerFrequency;
+ displaySettings();
+ sendSettings();
+}
+
+QByteArray XTRXInputGUI::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool XTRXInputGUI::deserialize(const QByteArray& data)
+{
+ if (m_settings.deserialize(data))
+ {
+ displaySettings();
+ m_forceSettings = true;
+ sendSettings();
+ return true;
+ }
+ else
+ {
+ resetToDefaults();
+ return false;
+ }
+}
+
+bool XTRXInputGUI::handleMessage(const Message& message)
+{
+
+ if (DeviceXTRXShared::MsgReportBuddyChange::match(message))
+ {
+ DeviceXTRXShared::MsgReportBuddyChange& report = (DeviceXTRXShared::MsgReportBuddyChange&) message;
+ m_settings.m_devSampleRate = report.getDevSampleRate();
+ m_settings.m_log2HardDecim = report.getLog2HardDecimInterp();
+
+ if (report.getRxElseTx()) {
+ m_settings.m_centerFrequency = report.getCenterFrequency();
+ }
+
+ blockApplySettings(true);
+ displaySettings();
+ blockApplySettings(false);
+
+ return true;
+ }
+ else if (DeviceXTRXShared::MsgReportClockSourceChange::match(message))
+ {
+ DeviceXTRXShared::MsgReportClockSourceChange& report = (DeviceXTRXShared::MsgReportClockSourceChange&) message;
+ m_settings.m_extClockFreq = report.getExtClockFeq();
+ m_settings.m_extClock = report.getExtClock();
+
+ blockApplySettings(true);
+ ui->extClock->setExternalClockFrequency(m_settings.m_extClockFreq);
+ ui->extClock->setExternalClockActive(m_settings.m_extClock);
+ blockApplySettings(false);
+
+ return true;
+ }
+ else if (XTRXInput::MsgReportStreamInfo::match(message))
+ {
+ XTRXInput::MsgReportStreamInfo& report = (XTRXInput::MsgReportStreamInfo&) message;
+
+ if (report.getSuccess())
+ {
+ if (report.getActive()) {
+ ui->streamStatusLabel->setStyleSheet("QLabel { background-color : green; }");
+ } else {
+ ui->streamStatusLabel->setStyleSheet("QLabel { background-color : blue; }");
+ }
+
+ ui->streamLinkRateText->setText(tr("%1 MB/s").arg(QString::number(report.getLinkRate() / 1000000.0f, 'f', 3)));
+
+ if (report.getUnderrun() > 0) {
+ ui->underrunLabel->setStyleSheet("QLabel { background-color : red; }");
+ } else {
+ ui->underrunLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
+ }
+
+ if (report.getOverrun() > 0) {
+ ui->overrunLabel->setStyleSheet("QLabel { background-color : red; }");
+ } else {
+ ui->overrunLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
+ }
+
+ if (report.getDroppedPackets() > 0) {
+ ui->droppedLabel->setStyleSheet("QLabel { background-color : red; }");
+ } else {
+ ui->droppedLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
+ }
+
+ ui->fifoBar->setMaximum(report.getFifoSize());
+ ui->fifoBar->setValue(report.getFifoFilledCount());
+ ui->fifoBar->setToolTip(tr("FIFO fill %1/%2 samples").arg(QString::number(report.getFifoFilledCount())).arg(QString::number(report.getFifoSize())));
+ }
+ else
+ {
+ ui->streamStatusLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
+ }
+
+ return true;
+ }
+ else if (DeviceXTRXShared::MsgReportDeviceInfo::match(message))
+ {
+ DeviceXTRXShared::MsgReportDeviceInfo& report = (DeviceXTRXShared::MsgReportDeviceInfo&) message;
+ ui->temperatureText->setText(tr("%1C").arg(QString::number(report.getTemperature(), 'f', 0)));
+ return true;
+ }
+ else if (XTRXInput::MsgStartStop::match(message))
+ {
+ XTRXInput::MsgStartStop& notif = (XTRXInput::MsgStartStop&) message;
+ blockApplySettings(true);
+ ui->startStop->setChecked(notif.getStartStop());
+ blockApplySettings(false);
+
+ return true;
+ }
+ return false;
+}
+
+void XTRXInputGUI::handleInputMessages()
+{
+ Message* message;
+
+ while ((message = m_inputMessageQueue.pop()) != 0)
+ {
+ if (DSPSignalNotification::match(*message))
+ {
+ DSPSignalNotification* notif = (DSPSignalNotification*) message;
+ m_sampleRate = notif->getSampleRate();
+ m_deviceCenterFrequency = notif->getCenterFrequency();
+ qDebug("XTRXInputGUI::handleInputMessages: DSPSignalNotification: SampleRate: %d, CenterFrequency: %llu", notif->getSampleRate(), notif->getCenterFrequency());
+ updateSampleRateAndFrequency();
+
+ delete message;
+ }
+ else
+ {
+ if (handleMessage(*message)) {
+ delete message;
+ }
+ }
+ }
+}
+
+void XTRXInputGUI::updateADCRate()
+{
+ uint32_t adcRate = m_settings.m_devSampleRate * (1<adcRateLabel->setText(tr("%1k").arg(QString::number(adcRate / 1000.0f, 'g', 5)));
+ } else {
+ ui->adcRateLabel->setText(tr("%1M").arg(QString::number(adcRate / 1000000.0f, 'g', 5)));
+ }
+}
+
+void XTRXInputGUI::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 XTRXInputGUI::displaySettings()
+{
+ ui->extClock->setExternalClockFrequency(m_settings.m_extClockFreq);
+ ui->extClock->setExternalClockActive(m_settings.m_extClock);
+
+ ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
+ ui->sampleRate->setValue(m_settings.m_devSampleRate);
+
+ ui->dcOffset->setChecked(m_settings.m_dcBlock);
+ ui->iqImbalance->setChecked(m_settings.m_iqCorrection);
+
+ ui->hwDecim->setCurrentIndex(m_settings.m_log2HardDecim);
+ ui->swDecim->setCurrentIndex(m_settings.m_log2SoftDecim);
+
+ updateADCRate();
+
+ ui->lpf->setValue(m_settings.m_lpfBW / 1000);
+
+ ui->lpFIREnable->setChecked(m_settings.m_lpfFIREnable);
+ ui->lpFIR->setValue(m_settings.m_lpfFIRBW / 1000);
+
+ ui->gain->setValue(m_settings.m_gain);
+ ui->gainText->setText(tr("%1").arg(m_settings.m_gain));
+
+ ui->antenna->setCurrentIndex((int) m_settings.m_antennaPath);
+
+ ui->gainMode->setCurrentIndex((int) m_settings.m_gainMode);
+ ui->lnaGain->setValue(m_settings.m_lnaGain);
+ ui->tiaGain->setCurrentIndex(m_settings.m_tiaGain - 1);
+ ui->pgaGain->setValue(m_settings.m_pgaGain);
+
+ if (m_settings.m_gainMode == XTRXInputSettings::GAIN_AUTO)
+ {
+ ui->gain->setEnabled(true);
+ ui->lnaGain->setEnabled(false);
+ ui->tiaGain->setEnabled(false);
+ ui->pgaGain->setEnabled(false);
+ }
+ else
+ {
+ ui->gain->setEnabled(false);
+ ui->lnaGain->setEnabled(true);
+ ui->tiaGain->setEnabled(true);
+ ui->pgaGain->setEnabled(true);
+ }
+
+ setNCODisplay();
+
+ ui->ncoEnable->setChecked(m_settings.m_ncoEnable);
+}
+
+void XTRXInputGUI::setNCODisplay()
+{
+ int ncoHalfRange = (m_settings.m_devSampleRate * (1<<(m_settings.m_log2HardDecim)))/2;
+ int lowBoundary = std::max(0, (int) m_settings.m_centerFrequency - ncoHalfRange);
+ ui->ncoFrequency->setValueRange(7,
+ lowBoundary/1000,
+ (m_settings.m_centerFrequency + ncoHalfRange)/1000); // frequency dial is in kHz
+ ui->ncoFrequency->setValue((m_settings.m_centerFrequency + m_settings.m_ncoFrequency)/1000);
+}
+
+void XTRXInputGUI::sendSettings()
+{
+ if(!m_updateTimer.isActive())
+ m_updateTimer.start(100);
+}
+
+void XTRXInputGUI::updateHardware()
+{
+ if (m_doApplySettings)
+ {
+ qDebug() << "XTRXInputGUI::updateHardware";
+ XTRXInput::MsgConfigureXTRX* message = XTRXInput::MsgConfigureXTRX::create(m_settings, m_forceSettings);
+ m_XTRXInput->getInputMessageQueue()->push(message);
+ m_forceSettings = false;
+ m_updateTimer.stop();
+ }
+}
+
+void XTRXInputGUI::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;
+ }
+
+ if (m_statusCounter < 1)
+ {
+ m_statusCounter++;
+ }
+ else
+ {
+ XTRXInput::MsgGetStreamInfo* message = XTRXInput::MsgGetStreamInfo::create();
+ m_XTRXInput->getInputMessageQueue()->push(message);
+ m_statusCounter = 0;
+ }
+
+ if (m_deviceStatusCounter < 10)
+ {
+ m_deviceStatusCounter++;
+ }
+ else
+ {
+ if (m_deviceUISet->m_deviceSourceAPI->isBuddyLeader())
+ {
+ XTRXInput::MsgGetDeviceInfo* message = XTRXInput::MsgGetDeviceInfo::create();
+ m_XTRXInput->getInputMessageQueue()->push(message);
+ }
+
+ m_deviceStatusCounter = 0;
+ }
+}
+
+void XTRXInputGUI::blockApplySettings(bool block)
+{
+ m_doApplySettings = !block;
+}
+
+void XTRXInputGUI::on_startStop_toggled(bool checked)
+{
+ if (m_doApplySettings)
+ {
+ XTRXInput::MsgStartStop *message = XTRXInput::MsgStartStop::create(checked);
+ m_XTRXInput->getInputMessageQueue()->push(message);
+ }
+}
+
+void XTRXInputGUI::on_record_toggled(bool checked)
+{
+ if (checked) {
+ ui->record->setStyleSheet("QToolButton { background-color : red; }");
+ } else {
+ ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
+ }
+
+ XTRXInput::MsgFileRecord* message = XTRXInput::MsgFileRecord::create(checked);
+ m_XTRXInput->getInputMessageQueue()->push(message);
+}
+
+void XTRXInputGUI::on_centerFrequency_changed(quint64 value)
+{
+ m_settings.m_centerFrequency = value * 1000;
+ setNCODisplay();
+ sendSettings();
+}
+
+void XTRXInputGUI::on_ncoFrequency_changed(quint64 value)
+{
+ m_settings.m_ncoFrequency = (int64_t) value - (int64_t) m_settings.m_centerFrequency/1000;
+ m_settings.m_ncoFrequency *= 1000;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_ncoEnable_toggled(bool checked)
+{
+ m_settings.m_ncoEnable = checked;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_ncoReset_clicked(bool checked __attribute__((unused)))
+{
+ m_settings.m_ncoFrequency = 0;
+ ui->ncoFrequency->setValue(m_settings.m_centerFrequency/1000);
+ sendSettings();
+}
+
+void XTRXInputGUI::on_dcOffset_toggled(bool checked)
+{
+ m_settings.m_dcBlock = checked;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_iqImbalance_toggled(bool checked)
+{
+ m_settings.m_iqCorrection = checked;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_sampleRate_changed(quint64 value)
+{
+ m_settings.m_devSampleRate = value;
+ updateADCRate();
+ setNCODisplay();
+ sendSettings();}
+
+void XTRXInputGUI::on_hwDecim_currentIndexChanged(int index)
+{
+ if ((index <0) || (index > 5))
+ return;
+ m_settings.m_log2HardDecim = index;
+ updateADCRate();
+ setNCODisplay();
+ sendSettings();
+}
+
+void XTRXInputGUI::on_swDecim_currentIndexChanged(int index)
+{
+ if ((index <0) || (index > 6))
+ return;
+ m_settings.m_log2SoftDecim = index;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_lpf_changed(quint64 value)
+{
+ m_settings.m_lpfBW = value * 1000;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_lpFIREnable_toggled(bool checked)
+{
+ m_settings.m_lpfFIREnable = checked;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_lpFIR_changed(quint64 value)
+{
+ m_settings.m_lpfFIRBW = value * 1000;
+
+ if (m_settings.m_lpfFIREnable) { // do not send the update if the FIR is disabled
+ sendSettings();
+ }
+}
+
+void XTRXInputGUI::on_gainMode_currentIndexChanged(int index)
+{
+ m_settings.m_gainMode = (XTRXInputSettings::GainMode) index;
+
+ if (index == 0)
+ {
+ ui->gain->setEnabled(true);
+ ui->lnaGain->setEnabled(false);
+ ui->tiaGain->setEnabled(false);
+ ui->pgaGain->setEnabled(false);
+ }
+ else
+ {
+ ui->gain->setEnabled(false);
+ ui->lnaGain->setEnabled(true);
+ ui->tiaGain->setEnabled(true);
+ ui->pgaGain->setEnabled(true);
+ }
+
+ sendSettings();
+}
+
+void XTRXInputGUI::on_gain_valueChanged(int value)
+{
+ m_settings.m_gain = value;
+ ui->gainText->setText(tr("%1").arg(m_settings.m_gain));
+ sendSettings();
+}
+
+void XTRXInputGUI::on_lnaGain_valueChanged(int value)
+{
+ m_settings.m_lnaGain = value;
+ ui->lnaGainText->setText(tr("%1").arg(m_settings.m_lnaGain));
+ sendSettings();
+}
+
+void XTRXInputGUI::on_tiaGain_currentIndexChanged(int index)
+{
+ m_settings.m_tiaGain = index + 1;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_pgaGain_valueChanged(int value)
+{
+ m_settings.m_pgaGain = value;
+ ui->pgaGainText->setText(tr("%1").arg(m_settings.m_pgaGain));
+ sendSettings();
+}
+
+void XTRXInputGUI::on_antenna_currentIndexChanged(int index)
+{
+ m_settings.m_antennaPath = (xtrx_antenna_t) index;
+ sendSettings();
+}
+
+void XTRXInputGUI::on_extClock_clicked()
+{
+ m_settings.m_extClock = ui->extClock->getExternalClockActive();
+ m_settings.m_extClockFreq = ui->extClock->getExternalClockFrequency();
+ qDebug("XTRXInputGUI::on_extClock_clicked: %u Hz %s", m_settings.m_extClockFreq, m_settings.m_extClock ? "on" : "off");
+ sendSettings();
+}
+
+void XTRXInputGUI::on_pwrmode_currentIndexChanged(int index)
+{
+ m_settings.m_pwrmode = index;
+ sendSettings();
+}
diff --git a/plugins/samplesource/xtrxinput/xtrxinputgui.h b/plugins/samplesource/xtrxinput/xtrxinputgui.h
new file mode 100644
index 000000000..133e119c9
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputgui.h
@@ -0,0 +1,107 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB //
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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_XTRXINPUT_XTRXINPUTGUI_H_
+#define PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTGUI_H_
+
+#include
+#include
+#include
+
+#include "util/messagequeue.h"
+
+#include "xtrxinput.h"
+
+class DeviceUISet;
+
+namespace Ui {
+class XTRXInputGUI;
+}
+
+class XTRXInputGUI : public QWidget, public PluginInstanceGUI {
+ Q_OBJECT
+
+public:
+ explicit XTRXInputGUI(DeviceUISet *deviceUISet, QWidget* parent = 0);
+ virtual ~XTRXInputGUI();
+ 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::XTRXInputGUI* ui;
+
+ DeviceUISet* m_deviceUISet;
+ XTRXInput* m_XTRXInput; //!< Same object as above but gives easy access to XTRXInput methods and attributes that are used intensively
+ XTRXInputSettings m_settings;
+ QTimer m_updateTimer;
+ QTimer m_statusTimer;
+ int m_sampleRate;
+ quint64 m_deviceCenterFrequency; //!< Center frequency in device
+ int m_lastEngineState;
+ bool m_doApplySettings;
+ bool m_forceSettings;
+ int m_statusCounter;
+ int m_deviceStatusCounter;
+ MessageQueue m_inputMessageQueue;
+
+ void displaySettings();
+ void setNCODisplay();
+ void sendSettings();
+ void updateSampleRateAndFrequency();
+ void updateADCRate();
+ void blockApplySettings(bool block);
+
+private slots:
+ void handleInputMessages();
+ 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);
+ void on_hwDecim_currentIndexChanged(int index);
+ void on_swDecim_currentIndexChanged(int index);
+ void on_lpf_changed(quint64 value);
+ void on_lpFIREnable_toggled(bool checked);
+ void on_lpFIR_changed(quint64 value);
+ void on_gainMode_currentIndexChanged(int index);
+ void on_gain_valueChanged(int value);
+ void on_lnaGain_valueChanged(int value);
+ void on_tiaGain_currentIndexChanged(int index);
+ void on_pgaGain_valueChanged(int value);
+ void on_antenna_currentIndexChanged(int index);
+ void on_extClock_clicked();
+ void on_pwrmode_currentIndexChanged(int index);
+
+ void updateHardware();
+ void updateStatus();
+};
+
+#endif /* PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTGUI_H_ */
diff --git a/plugins/samplesource/xtrxinput/xtrxinputgui.ui b/plugins/samplesource/xtrxinput/xtrxinputgui.ui
new file mode 100644
index 000000000..62a08dd65
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputgui.ui
@@ -0,0 +1,1215 @@
+
+
+ XTRXInputGUI
+
+
+
+ 0
+ 0
+ 423
+ 290
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 350
+ 290
+
+
+
+
+ Sans Serif
+ 9
+
+
+
+ LimeSDR Input
+
+
+
+ 3
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+ -
+
+
+ 4
+
+
-
+
+
-
+
+
-
+
+
+ start/stop acquisition
+
+
+
+
+
+
+ :/play.png
+ :/stop.png:/play.png
+
+
+
+ -
+
+
+ Toggle record I/Q samples from device
+
+
+
+
+
+
+ :/record_off.png
+ :/record_on.png:/record_off.png
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 54
+ 0
+
+
+
+ ADC rate before hardware downsampling (k or MS/s)
+
+
+ 00000k
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ DejaVu Sans Mono
+ 20
+ 50
+ false
+
+
+
+ PointingHandCursor
+
+
+ Qt::StrongFocus
+
+
+ Main center frequency in kHz
+
+
+
+ -
+
+
+ 6
+
+
+ 6
+
+
-
+
+
-
+
+
+ kHz
+
+
+
+ -
+
+
+
+ 20
+ 0
+
+
+
+ Channel number
+
+
+ #0
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 54
+ 0
+
+
+
+ Baseband I/Q sample rate kS/s
+
+
+ 00000k
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+
+ -
+
+
+ 2
+
+
-
+
+
+ Enable the TSP NCO
+
+
+ NCO
+
+
+
+ -
+
+
+
+ 22
+ 22
+
+
+
+ Reset the NCO to zero frequency
+
+
+ R
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ DejaVu Sans Mono
+ 12
+ 50
+ false
+
+
+
+ PointingHandCursor
+
+
+ Center frequency with NCO engaged (kHz)
+
+
+
+ -
+
+
+ kHz
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Automatic DC offset removal
+
+
+ DC
+
+
+
+ -
+
+
+ Automatic IQ imbalance correction
+
+
+ IQ
+
+
+
+ -
+
+
+ External clock dialog
+
+
+
+
+
+
+ :/clocksource.png:/clocksource.png
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 2
+
+
-
+
+
+ Hw
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 50
+ 16777215
+
+
+
+ TSP hardware decimation factor
+
+
+ 0
+
+
-
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 4
+
+
+ -
+
+ 8
+
+
+ -
+
+ 16
+
+
+ -
+
+ 32
+
+
+
+
+ -
+
+
+ Sw
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 50
+ 16777215
+
+
+
+ Software decimation factor
+
+
+ 0
+
+
-
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 4
+
+
+ -
+
+ 8
+
+
+ -
+
+ 16
+
+
+ -
+
+ 32
+
+
+ -
+
+ 64
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ SR
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ DejaVu Sans Mono
+ 12
+ 50
+ false
+
+
+
+ PointingHandCursor
+
+
+ Device to host sample rate
+
+
+
+ -
+
+
+ S/s
+
+
+
+ -
+
+
+
+ 50
+ 0
+
+
+
+
+
+
+ 4
+
+
-
+
+ 0 - Save Max
+
+
+ -
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 3 - Economy
+
+
+ -
+
+ 4 - Optimal
+
+
+ -
+
+ 5
+
+
+ -
+
+ 6
+
+
+ -
+
+ 7 - Perf Max
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 2
+
+
+ 2
+
+
-
+
+
+ LP
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ DejaVu Sans Mono
+ 12
+ 50
+ false
+
+
+
+ PointingHandCursor
+
+
+ Analog lowpass filer bandwidth (kHz)
+
+
+
+ -
+
+
+ kHz
+
+
+
+ -
+
+
+ Enable or disable TSP digital FIR lowpass filters
+
+
+ FIR
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ DejaVu Sans Mono
+ 12
+
+
+
+ PointingHandCursor
+
+
+ Digital FIR lowpass filers bandwidth (kHz)
+
+
+
+ -
+
+
+ kHz
+
+
+
+
+
+ -
+
+
+ 2
+
+
+ 2
+
+
-
+
+
+
+ 54
+ 16777215
+
+
+
+ Automatic or Manual gain selection
+
+
-
+
+ Aut
+
+
+ -
+
+ Man
+
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ Automatic global gain (dB)
+
+
+ 70
+
+
+ 1
+
+
+ 20
+
+
+
+ -
+
+
+
+ 18
+ 0
+
+
+
+
+ 18
+ 16777215
+
+
+
+ Automatic global gain
+
+
+ 20
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ Manual LNA gain
+
+
+ 1
+
+
+ 30
+
+
+ 1
+
+
+ 15
+
+
+
+ -
+
+
+
+ 18
+ 0
+
+
+
+
+ 18
+ 16777215
+
+
+
+ Manual LNA gain (dB)
+
+
+ 15
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 40
+ 16777215
+
+
+
+ Manual TIA gain (dB)
+
+
+ 1
+
+
-
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 3
+
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ Manual PGA gain
+
+
+ 32
+
+
+ 1
+
+
+ 16
+
+
+
+ -
+
+
+
+ 18
+ 0
+
+
+
+
+ 18
+ 16777215
+
+
+
+ Manual PGA gain (dB)
+
+
+ 16
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ :/antenna.png
+
+
+
+ -
+
+
+
+ 50
+ 0
+
+
+
+
+ 50
+ 16777215
+
+
+
+ Antenna select: No: none, Lo: 700:900M, Hi: 2:2.6G, Wi: wideband, T1: Tx1 LB, T2: Tx2 LB
+
+
-
+
+ Lo
+
+
+ -
+
+ Wide
+
+
+ -
+
+ Hi
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 2
+
+
+ 2
+
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+ Green when stream is reporting data
+
+
+
+
+
+ :/stream.png
+
+
+
+ -
+
+
+
+ 12
+ 0
+
+
+
+ Red if underruns
+
+
+ background:rgb(79,79,79);
+
+
+ U
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 12
+ 0
+
+
+
+ Red if overruns
+
+
+ background:rgb(79,79,79);
+
+
+ O
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 12
+ 0
+
+
+
+ Red if dropped packets
+
+
+ background:rgb(79,79,79);
+
+
+ D
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 90
+ 0
+
+
+
+ Stream link rate (MB/s)
+
+
+ 000.000 MB/s
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 16777215
+ 16
+
+
+
+
+ 8
+
+
+
+ FIFO fill status
+
+
+ QProgressBar{border: 2px solid rgb(79, 79, 79); text-align: center;}
+QToolTip{background-color: white; color: black;}
+
+
+ 0
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 24
+ 0
+
+
+
+ Board temperature (degrees C)
+
+
+ 00C
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+ ValueDial
+ QWidget
+
+ 1
+
+
+ ButtonSwitch
+ QToolButton
+
+
+
+ ExternalClockButton
+ QToolButton
+ gui/externalclockbutton.h
+
+
+
+
+
+
+
diff --git a/plugins/samplesource/xtrxinput/xtrxinputplugin.cpp b/plugins/samplesource/xtrxinput/xtrxinputplugin.cpp
new file mode 100644
index 000000000..a2632ec93
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputplugin.cpp
@@ -0,0 +1,145 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB //
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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 "xtrxinputplugin.h"
+
+#include
+
+#include
+#include
+
+#include "xtrx_api.h"
+#include "plugin/pluginapi.h"
+#include "util/simpleserializer.h"
+#include "device/devicesourceapi.h"
+
+#ifdef SERVER_MODE
+#include "xtrxinput.h"
+#else
+#include "xtrxinputgui.h"
+#endif
+
+const PluginDescriptor XTRXInputPlugin::m_pluginDescriptor = {
+ QString("XTRX Input"),
+ QString("0.0.1"),
+ QString("(c) Sergey Kostanbaev, Fairwaves"),
+ QString("https://github.com/xtrx-sdr/sdrangel"),
+ true,
+ QString("https://github.com/xtrx-sdr/sdrangel")
+};
+
+const QString XTRXInputPlugin::m_hardwareID = "XTRX";
+const QString XTRXInputPlugin::m_deviceTypeID = XTRX_DEVICE_TYPE_ID;
+
+XTRXInputPlugin::XTRXInputPlugin(QObject* parent) :
+ QObject(parent)
+{
+}
+
+const PluginDescriptor& XTRXInputPlugin::getPluginDescriptor() const
+{
+ return m_pluginDescriptor;
+}
+
+void XTRXInputPlugin::initPlugin(PluginAPI* pluginAPI)
+{
+ pluginAPI->registerSampleSource(m_deviceTypeID, this);
+}
+
+PluginInterface::SamplingDevices XTRXInputPlugin::enumSampleSources()
+{
+ SamplingDevices result;
+ xtrx_device_info_t devs[32];
+ int res = xtrx_discovery(devs, 32);
+ int i;
+ for (i = 0; i < res; i++) {
+ DeviceXTRXParams XTRXParams;
+ for (unsigned int j = 0; j < XTRXParams.m_nbRxChannels; j++)
+ {
+ qDebug("XTRXInputPlugin::enumSampleSources: device #%d channel %u: %s", i, j, devs[i].uniqname);
+ QString displayedName(QString("XTRX[%1:%2] %3").arg(i).arg(j).arg(devs[i].uniqname));
+ result.append(SamplingDevice(displayedName,
+ m_hardwareID,
+ m_deviceTypeID,
+ QString(devs[i].uniqname),
+ i,
+ PluginInterface::SamplingDevice::PhysicalDevice,
+ true,
+ XTRXParams.m_nbRxChannels,
+ j));
+ }
+ }
+ return result;
+}
+
+#ifdef SERVER_MODE
+PluginInstanceGUI* XTRXInputPlugin::createSampleSourcePluginInstanceGUI(
+ const QString& sourceId __attribute((unused)),
+ QWidget **widget __attribute((unused)),
+ DeviceUISet *deviceUISet __attribute((unused)))
+{
+ return 0;
+}
+#else
+PluginInstanceGUI* XTRXInputPlugin::createSampleSourcePluginInstanceGUI(
+ const QString& sourceId,
+ QWidget **widget,
+ DeviceUISet *deviceUISet)
+{
+ if(sourceId == m_deviceTypeID)
+ {
+ XTRXInputGUI* gui = new XTRXInputGUI(deviceUISet);
+ *widget = gui;
+ return gui;
+ }
+ else
+ {
+ return 0;
+ }
+}
+#endif
+
+bool XTRXInputPlugin::findSerial(const char *lmsInfoStr, std::string& serial)
+{
+ std::regex serial_reg("serial=([0-9,A-F]+)");
+ std::string input(lmsInfoStr);
+ std::smatch result;
+ std::regex_search(input, result, serial_reg);
+
+ if (result[1].str().length()>0)
+ {
+ serial = result[1].str();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+DeviceSampleSource *XTRXInputPlugin::createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI)
+{
+ if (sourceId == m_deviceTypeID)
+ {
+ XTRXInput* input = new XTRXInput(deviceAPI);
+ return input;
+ }
+ else
+ {
+ return 0;
+ }
+}
diff --git a/plugins/samplesource/xtrxinput/xtrxinputplugin.h b/plugins/samplesource/xtrxinput/xtrxinputplugin.h
new file mode 100644
index 000000000..493e7ae16
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputplugin.h
@@ -0,0 +1,55 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB //
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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_XTRXINPUT_XTRXINPUTPLUGIN_H_
+#define PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTPLUGIN_H_
+
+#include
+#include "plugin/plugininterface.h"
+
+class PluginAPI;
+
+#define XTRX_DEVICE_TYPE_ID "sdrangel.samplesource.xtrx"
+
+class XTRXInputPlugin : public QObject, public PluginInterface {
+ Q_OBJECT
+ Q_INTERFACES(PluginInterface)
+ Q_PLUGIN_METADATA(IID XTRX_DEVICE_TYPE_ID)
+
+public:
+ explicit XTRXInputPlugin(QObject* parent = 0);
+
+ const PluginDescriptor& getPluginDescriptor() const;
+ void initPlugin(PluginAPI* pluginAPI);
+
+ virtual SamplingDevices enumSampleSources();
+ virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(
+ const QString& sourceId,
+ QWidget **widget,
+ DeviceUISet *deviceUISet);
+ virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI);
+
+ static const QString m_hardwareID;
+ static const QString m_deviceTypeID;
+
+private:
+ static const PluginDescriptor m_pluginDescriptor;
+ static bool findSerial(const char *lmsInfoStr, std::string& serial);
+};
+
+
+#endif /* PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTPLUGIN_H_ */
diff --git a/plugins/samplesource/xtrxinput/xtrxinputsettings.cpp b/plugins/samplesource/xtrxinput/xtrxinputsettings.cpp
new file mode 100644
index 000000000..e2970da6a
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputsettings.cpp
@@ -0,0 +1,120 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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 "util/simpleserializer.h"
+#include "xtrxinputsettings.h"
+
+XTRXInputSettings::XTRXInputSettings()
+{
+ resetToDefaults();
+}
+
+void XTRXInputSettings::resetToDefaults()
+{
+ m_centerFrequency = 435000*1000;
+ m_devSampleRate = 5e6;
+ m_log2HardDecim = 1;
+ m_dcBlock = false;
+ m_iqCorrection = false;
+ m_log2SoftDecim = 0;
+ m_lpfBW = 4.5e6f;
+ m_lpfFIREnable = false;
+ m_lpfFIRBW = 2.5e6f;
+ m_gain = 50;
+ m_ncoEnable = false;
+ m_ncoFrequency = 0;
+ m_antennaPath = XTRX_RX_L;
+ m_gainMode = GAIN_AUTO;
+ m_lnaGain = 15;
+ m_tiaGain = 2;
+ m_pgaGain = 16;
+ m_extClock = false;
+ m_extClockFreq = 0; // Auto
+ m_pwrmode = 1;
+}
+
+QByteArray XTRXInputSettings::serialize() const
+{
+ SimpleSerializer s(1);
+
+ s.writeDouble(1, m_devSampleRate);
+ s.writeU32(2, m_log2HardDecim);
+ s.writeBool(3, m_dcBlock);
+ s.writeBool(4, m_iqCorrection);
+ s.writeU32(5, m_log2SoftDecim);
+ s.writeFloat(7, m_lpfBW);
+ s.writeBool(8, m_lpfFIREnable);
+ s.writeFloat(9, m_lpfFIRBW);
+ s.writeU32(10, m_gain);
+ s.writeBool(11, m_ncoEnable);
+ s.writeS32(12, m_ncoFrequency);
+ s.writeS32(13, (int) m_antennaPath);
+ s.writeS32(14, (int) m_gainMode);
+ s.writeU32(15, m_lnaGain);
+ s.writeU32(16, m_tiaGain);
+ s.writeU32(17, m_pgaGain);
+ s.writeBool(18, m_extClock);
+ s.writeU32(19, m_extClockFreq);
+ s.writeU32(20, m_pwrmode);
+
+ return s.final();
+}
+
+bool XTRXInputSettings::deserialize(const QByteArray& data)
+{
+ SimpleDeserializer d(data);
+
+ if (!d.isValid())
+ {
+ resetToDefaults();
+ return false;
+ }
+
+ if (d.getVersion() == 1)
+ {
+ int intval;
+
+ d.readDouble(1, &m_devSampleRate, 5e6);
+ d.readU32(2, &m_log2HardDecim, 2);
+ d.readBool(3, &m_dcBlock, false);
+ d.readBool(4, &m_iqCorrection, false);
+ d.readU32(5, &m_log2SoftDecim, 0);
+ d.readFloat(7, &m_lpfBW, 1.5e6);
+ d.readBool(8, &m_lpfFIREnable, false);
+ d.readFloat(9, &m_lpfFIRBW, 1.5e6);
+ d.readU32(10, &m_gain, 50);
+ d.readBool(11, &m_ncoEnable, false);
+ d.readS32(12, &m_ncoFrequency, 0);
+ d.readS32(13, &intval, 0);
+ m_antennaPath = (xtrx_antenna_t) intval;
+ d.readS32(14, &intval, 0);
+ m_gainMode = (GainMode) intval;
+ d.readU32(15, &m_lnaGain, 15);
+ d.readU32(16, &m_tiaGain, 2);
+ d.readU32(17, &m_pgaGain, 16);
+ d.readBool(18, &m_extClock, false);
+ d.readU32(19, &m_extClockFreq, 0);
+ d.readU32(20, &m_pwrmode, 2);
+
+ return true;
+ }
+ else
+ {
+ resetToDefaults();
+ return false;
+ }
+
+}
diff --git a/plugins/samplesource/xtrxinput/xtrxinputsettings.h b/plugins/samplesource/xtrxinput/xtrxinputsettings.h
new file mode 100644
index 000000000..9d3cc304d
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputsettings.h
@@ -0,0 +1,71 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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_XTRXINPUT_XTRXINPUTSETTINGS_H_
+#define PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTSETTINGS_H_
+
+#include
+#include
+
+#include "xtrx_api.h"
+
+/**
+ * These are the settings individual to each hardware channel or software Rx chain
+ * Plus the settings to be saved in the presets
+ */
+struct XTRXInputSettings
+{
+ typedef enum {
+ FC_POS_INFRA = 0,
+ FC_POS_SUPRA,
+ FC_POS_CENTER
+ } fcPos_t;
+
+ typedef enum {
+ GAIN_AUTO,
+ GAIN_MANUAL
+ } GainMode;
+
+ // global settings to be saved
+ uint64_t m_centerFrequency;
+ double m_devSampleRate;
+ uint32_t m_log2HardDecim;
+ // channel settings
+ bool m_dcBlock;
+ bool m_iqCorrection;
+ uint32_t m_log2SoftDecim;
+ float m_lpfBW; //!< LMS amalog lowpass filter bandwidth (Hz)
+ 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)
+ xtrx_antenna_t m_antennaPath;
+ GainMode m_gainMode; //!< Gain mode: auto or manual
+ uint32_t m_lnaGain; //!< Manual LAN gain
+ uint32_t m_tiaGain; //!< Manual TIA gain
+ uint32_t m_pgaGain; //!< Manual PGA gain
+ bool m_extClock; //!< True if external clock source
+ uint32_t m_extClockFreq; //!< Frequency (Hz) of external clock source
+ uint32_t m_pwrmode;
+
+ XTRXInputSettings();
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+};
+
+#endif /* PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTSETTINGS_H_ */
diff --git a/plugins/samplesource/xtrxinput/xtrxinputthread.cpp b/plugins/samplesource/xtrxinput/xtrxinputthread.cpp
new file mode 100644
index 000000000..d667606eb
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputthread.cpp
@@ -0,0 +1,229 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB //
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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 "xtrxinputsettings.h"
+#include "xtrxinputthread.h"
+
+XTRXInputThread::XTRXInputThread(DeviceXTRXShared* shared,
+ SampleSinkFifo* sampleFifo,
+ QObject* parent) :
+ QThread(parent),
+ m_running(false),
+ m_convertBuffer(XTRX_BLOCKSIZE),
+ m_sampleFifo(sampleFifo),
+ m_log2Decim(0),
+ m_fcPos(XTRXInputSettings::FC_POS_CENTER),
+ m_shared(shared)
+{
+}
+
+XTRXInputThread::~XTRXInputThread()
+{
+ stopWork();
+}
+
+void XTRXInputThread::startWork()
+{
+ if (m_running) return; // return if running already
+
+ xtrx_run_params params;
+ xtrx_run_params_init(¶ms);
+
+ params.dir = XTRX_RX;
+ params.rx.chs = XTRX_CH_AB;
+ params.rx.wfmt = XTRX_WF_16;
+ params.rx.hfmt = XTRX_IQ_INT16;
+ params.rx.flags |= XTRX_RSP_SISO_MODE;
+ params.rx_stream_start = 2*8192;
+
+ // TODO: replace this
+ if (m_shared->m_channel == XTRX_CH_B)
+ params.rx.flags |= XTRX_RSP_SWAP_AB;
+
+ int res = xtrx_run_ex(m_shared->m_deviceParams->getDevice(),
+ ¶ms);
+
+ if (res != 0) {
+ qCritical("XTRXInputThread::startWork: could not start stream err:%d", res);
+ } else {
+ usleep(50000);
+ qDebug("XTRXInputThread::startWork: stream started");
+ }
+
+ m_startWaitMutex.lock();
+ start();
+ while(!m_running)
+ m_startWaiter.wait(&m_startWaitMutex, 100);
+ m_startWaitMutex.unlock();
+}
+
+void XTRXInputThread::stopWork()
+{
+ if (!m_running) return; // return if not running
+
+ m_running = false;
+
+ int res = xtrx_stop(m_shared->m_deviceParams->getDevice(), XTRX_RX);
+ wait();
+
+
+ if (res != 0) {
+ qCritical("XTRXInputThread::stopWork: could not stop stream");
+ } else {
+ usleep(50000);
+ qDebug("XTRXInputThread::stopWork: stream stopped");
+ }
+}
+
+void XTRXInputThread::setLog2Decimation(unsigned int log2_decim)
+{
+ m_log2Decim = log2_decim;
+}
+
+void XTRXInputThread::setFcPos(int fcPos)
+{
+ m_fcPos = fcPos;
+}
+
+void XTRXInputThread::run()
+{
+ int res;
+
+ m_running = true;
+ m_startWaiter.wakeAll();
+
+ void* buffers[1] = { m_buf };
+ xtrx_recv_ex_info_t nfo;
+ nfo.samples = XTRX_BLOCKSIZE;
+ nfo.buffer_count = 1;
+ nfo.buffers = (void* const*)buffers;
+ nfo.flags = RCVEX_DONT_INSER_ZEROS | RCVEX_DROP_OLD_ON_OVERFLOW;
+
+
+ while (m_running)
+ {
+ //if ((res = LMS_RecvStream(m_stream, (void *) m_buf, XTRX_BLOCKSIZE, &metadata, 1000)) < 0)
+ res = xtrx_recv_sync_ex(m_shared->m_deviceParams->getDevice(),
+ &nfo);
+
+ if (res < 0)
+ {
+ qCritical("XTRXInputThread::run read error: %d", res);
+ break;
+ }
+
+ callback(m_buf, 2 * nfo.out_samples);
+ }
+
+ m_running = false;
+}
+
+// Decimate according to specified log2 (ex: log2=4 => decim=16)
+void XTRXInputThread::callback(const qint16* buf, qint32 len)
+{
+ SampleVector::iterator it = m_convertBuffer.begin();
+
+ if (m_log2Decim == 0)
+ {
+ m_decimators.decimate1(&it, buf, len);
+ }
+ else
+ {
+ if (m_fcPos == 0) // Infra
+ {
+ switch (m_log2Decim)
+ {
+ case 1:
+ m_decimators.decimate2_inf(&it, buf, len);
+ break;
+ case 2:
+ m_decimators.decimate4_inf(&it, buf, len);
+ break;
+ case 3:
+ m_decimators.decimate8_inf(&it, buf, len);
+ break;
+ case 4:
+ m_decimators.decimate16_inf(&it, buf, len);
+ break;
+ case 5:
+ m_decimators.decimate32_inf(&it, buf, len);
+ break;
+ case 6:
+ m_decimators.decimate64_inf(&it, buf, len);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (m_fcPos == 1) // Supra
+ {
+ switch (m_log2Decim)
+ {
+ case 1:
+ m_decimators.decimate2_sup(&it, buf, len);
+ break;
+ case 2:
+ m_decimators.decimate4_sup(&it, buf, len);
+ break;
+ case 3:
+ m_decimators.decimate8_sup(&it, buf, len);
+ break;
+ case 4:
+ m_decimators.decimate16_sup(&it, buf, len);
+ break;
+ case 5:
+ m_decimators.decimate32_sup(&it, buf, len);
+ break;
+ case 6:
+ m_decimators.decimate64_sup(&it, buf, len);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (m_fcPos == 2) // Center
+ {
+ switch (m_log2Decim)
+ {
+ case 1:
+ m_decimators.decimate2_cen(&it, buf, len);
+ break;
+ case 2:
+ m_decimators.decimate4_cen(&it, buf, len);
+ break;
+ case 3:
+ m_decimators.decimate8_cen(&it, buf, len);
+ break;
+ case 4:
+ m_decimators.decimate16_cen(&it, buf, len);
+ break;
+ case 5:
+ m_decimators.decimate32_cen(&it, buf, len);
+ break;
+ case 6:
+ m_decimators.decimate64_cen(&it, buf, len);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ m_sampleFifo->write(m_convertBuffer.begin(), it);
+}
diff --git a/plugins/samplesource/xtrxinput/xtrxinputthread.h b/plugins/samplesource/xtrxinput/xtrxinputthread.h
new file mode 100644
index 000000000..e2ae68ab1
--- /dev/null
+++ b/plugins/samplesource/xtrxinput/xtrxinputthread.h
@@ -0,0 +1,70 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB //
+// Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. //
+// //
+// 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_XTRXINPUT_XTRXINPUTTHREAD_H_
+#define PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTTHREAD_H_
+
+#include
+#include
+#include
+
+#include "xtrx_api.h"
+
+#include "dsp/samplesinkfifo.h"
+#include "dsp/decimators.h"
+#include "xtrx/devicextrxshared.h"
+
+#define XTRX_BLOCKSIZE (1<<13) //complex samples per buffer
+
+class XTRXInputThread : public QThread, public DeviceXTRXShared::ThreadInterface
+{
+ Q_OBJECT
+
+public:
+ XTRXInputThread(DeviceXTRXShared* shared, SampleSinkFifo* sampleFifo, QObject* parent = 0);
+ ~XTRXInputThread();
+
+ virtual void startWork();
+ virtual void stopWork();
+ virtual void setDeviceSampleRate(int sampleRate __attribute__((unused))) {}
+ virtual bool isRunning() { return m_running; }
+ void setLog2Decimation(unsigned int log2_decim);
+ void setFcPos(int fcPos);
+
+private:
+ QMutex m_startWaitMutex;
+ QWaitCondition m_startWaiter;
+ bool m_running;
+
+ qint16 m_buf[2*XTRX_BLOCKSIZE]; //must hold I+Q values of each sample hence 2xcomplex size
+ SampleVector m_convertBuffer;
+ SampleSinkFifo* m_sampleFifo;
+
+ unsigned int m_log2Decim; // soft decimation
+ int m_fcPos;
+
+ Decimators m_decimators;
+
+ DeviceXTRXShared* m_shared;
+
+ void run();
+ void callback(const qint16* buf, qint32 len);
+};
+
+
+
+#endif /* PLUGINS_SAMPLESOURCE_XTRXINPUT_XTRXINPUTTHREAD_H_ */
diff --git a/pluginssrv/samplesource/CMakeLists.txt b/pluginssrv/samplesource/CMakeLists.txt
index 5bcb15917..a4204abbd 100644
--- a/pluginssrv/samplesource/CMakeLists.txt
+++ b/pluginssrv/samplesource/CMakeLists.txt
@@ -54,6 +54,11 @@ if(LIBUSB_FOUND AND RX_SAMPLE_24BIT AND LIBPERSEUS_FOUND)
add_subdirectory(perseus)
endif(LIBUSB_FOUND AND RX_SAMPLE_24BIT AND LIBPERSEUS_FOUND)
+find_package(LibXTRX)
+if(LIBXTRX_FOUND)
+ add_subdirectory(xtrxinput)
+endif(LIBXTRX_FOUND)
+
find_package(LibIIO)
if(LIBUSB_FOUND AND LIBIIO_FOUND)
add_subdirectory(plutosdrinput)
@@ -97,6 +102,7 @@ if (BUILD_DEBIAN)
add_subdirectory(rtlsdr)
add_subdirectory(sdrdaemonsource)
add_subdirectory(sdrplay)
+ add_subdirectory(xtrxinput)
endif (BUILD_DEBIAN)
add_subdirectory(filesource)
diff --git a/pluginssrv/samplesource/xtrxinput/CMakeLists.txt b/pluginssrv/samplesource/xtrxinput/CMakeLists.txt
new file mode 100644
index 000000000..57ad4652b
--- /dev/null
+++ b/pluginssrv/samplesource/xtrxinput/CMakeLists.txt
@@ -0,0 +1,46 @@
+project(xtrxinput)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+set(PLUGIN_PREFIX "../../../plugins/samplesource/xtrxinput")
+
+set(xtrxinput_SOURCES
+ ${PLUGIN_PREFIX}/xtrxinput.cpp
+ ${PLUGIN_PREFIX}/xtrxinputplugin.cpp
+ ${PLUGIN_PREFIX}/xtrxinputsettings.cpp
+ ${PLUGIN_PREFIX}/xtrxinputthread.cpp
+)
+
+set(xtrxinput_HEADERS
+ ${PLUGIN_PREFIX}/xtrxinput.h
+ ${PLUGIN_PREFIX}/xtrxinputplugin.h
+ ${PLUGIN_PREFIX}/xtrxinputsettings.h
+ ${PLUGIN_PREFIX}/xtrxinputthread.h
+)
+
+include_directories(
+ .
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/devices
+ ${LIBXTRX_INCLUDE_DIRS}
+)
+
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_PLUGIN)
+add_definitions(-DQT_SHARED)
+
+add_library(inputxtrxsrv SHARED
+ ${xtrxinput_SOURCES}
+ ${xtrxinput_HEADERS_MOC}
+)
+
+
+target_link_libraries(inputxtrxsrv
+ ${QT_LIBRARIES}
+ ${LIBXTRX_LIBRARIES}
+ sdrbase
+ xtrxdevice
+)
+
+qt5_use_modules(inputxtrxsrv Core)
+
+install(TARGETS inputxtrxsrv DESTINATION lib/pluginssrv/samplesource)
\ No newline at end of file