diff --git a/plugins/samplesource/perseus/CMakeLists.txt b/plugins/samplesource/perseus/CMakeLists.txt new file mode 100644 index 000000000..57673ba22 --- /dev/null +++ b/plugins/samplesource/perseus/CMakeLists.txt @@ -0,0 +1,78 @@ +project(perseus) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +set(perseus_SOURCES +# perseusgui.cpp +# perseusinput.cpp +# perseusplugin.cpp + perseussettings.cpp +# perseusthread.cpp +) + +set(perseus_HEADERS +# perseusgui.h +# perseusinput.h +# perseusplugin.h + perseussettings.h +# perseusthread.h +) + +set(perseus_FORMS + perseusgui.ui +) + +if (BUILD_DEBIAN) +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${LIBAIRSPYHFSRC} + ${LIBAIRSPYHFSRC}/libperseus/src +) +else (BUILD_DEBIAN) +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${LIBAIRSPYHF_INCLUDE_DIR} +) +endif (BUILD_DEBIAN) + +#include(${QT_USE_FILE}) +#add_definitions(${QT_DEFINITIONS}) +add_definitions("${QT_DEFINITIONS} -DLIBAIRSPY_DYN_RATES") +add_definitions(-DQT_PLUGIN) +add_definitions(-DQT_SHARED) + +#qt4_wrap_cpp(perseus_HEADERS_MOC ${perseus_HEADERS}) +qt5_wrap_ui(perseus_FORMS_HEADERS ${perseus_FORMS}) + +add_library(inputperseus SHARED + ${perseus_SOURCES} + ${perseus_HEADERS_MOC} + ${perseus_FORMS_HEADERS} +) + +if (BUILD_DEBIAN) +target_link_libraries(inputperseus + ${QT_LIBRARIES} + perseus + sdrbase + sdrgui + swagger +) +else (BUILD_DEBIAN) +target_link_libraries(inputperseus + ${QT_LIBRARIES} + ${LIBAIRSPYHF_LIBRARIES} + sdrbase + sdrgui + swagger +) +endif (BUILD_DEBIAN) + + +qt5_use_modules(inputperseus Core Widgets) + +install(TARGETS inputperseus DESTINATION lib/plugins/samplesource) diff --git a/plugins/samplesource/perseus/perseusinput.cpp b/plugins/samplesource/perseus/perseusinput.cpp new file mode 100644 index 000000000..5f89f4c60 --- /dev/null +++ b/plugins/samplesource/perseus/perseusinput.cpp @@ -0,0 +1,199 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "SWGDeviceSettings.h" +#include "SWGDeviceState.h" + +#include "dsp/filerecord.h" +#include "dsp/dspcommands.h" +#include "dsp/dspengine.h" +#include "device/devicesourceapi.h" + +#include "perseusinput.h" +#include "perseusthread.h" + +MESSAGE_CLASS_DEFINITION(PerseusInput::MsgConfigurePerseus, Message) +MESSAGE_CLASS_DEFINITION(PerseusInput::MsgFileRecord, Message) +MESSAGE_CLASS_DEFINITION(PerseusInput::MsgStartStop, Message) + +PerseusInput::PerseusInput(DeviceSourceAPI *deviceAPI) : + m_deviceAPI(deviceAPI), + m_fileSink(0), + m_deviceDescription("PerseusInput"), + m_running(false), + m_perseusThread(0), + m_perseusDescriptor(0) +{ + openDevice(); + char recFileNameCStr[30]; + sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceAPI->getDeviceUID()); + m_fileSink = new FileRecord(std::string(recFileNameCStr)); + m_deviceAPI->addSink(m_fileSink); +} + +PerseusInput::~PerseusInput() +{ + m_deviceAPI->removeSink(m_fileSink); + delete m_fileSink; + closeDevice(); +} + +void PerseusInput::destroy() +{ + delete this; +} + +void PerseusInput::init() +{ + applySettings(m_settings, true); +} + +bool PerseusInput::start() +{ + if (m_running) stop(); + + applySettings(m_settings, true); + + // start / stop streaming is done in the thread. + + if ((m_plutoSDRInputThread = new PlutoSDRInputThread(PLUTOSDR_BLOCKSIZE_SAMPLES, m_deviceShared.m_deviceParams->getBox(), &m_sampleFifo)) == 0) + { + qFatal("PlutoSDRInput::start: cannot create thread"); + stop(); + return false; + } + else + { + qDebug("PlutoSDRInput::start: thread created"); + } + + m_perseusThread->setLog2Decimation(m_settings.m_log2Decim); + m_perseusThread->startWork(); + + m_running = true; + + return true; +} + +void PerseusInput::stop() +{ + if (m_perseusThread != 0) + { + m_perseusThread->stopWork(); + delete m_perseusThread; + m_perseusThread = 0; + } + + m_running = false; +} + +QByteArray PerseusInput::serialize() const +{ + return m_settings.serialize(); +} + +bool PerseusInput::deserialize(const QByteArray& data) +{ + bool success = true; + + if (!m_settings.deserialize(data)) + { + m_settings.resetToDefaults(); + success = false; + } + + MsgConfigurePerseus* message = MsgConfigurePerseus::create(m_settings, true); + m_inputMessageQueue.push(message); + + if (m_guiMessageQueue) + { + MsgConfigurePerseus* messageToGUI = MsgConfigurePerseus::create(m_settings, true); + m_guiMessageQueue->push(messageToGUI); + } + + return success; +} + +const QString& PerseusInput::getDeviceDescription() const +{ + return m_deviceDescription; +} +int PerseusInput::getSampleRate() const +{ + return (m_settings.m_devSampleRate / (1<push(messageToGUI); + } +} + +bool PerseusInput::openDevice() +{ + m_deviceAPI->getSampleSourceSerial(); + int deviceSequence = DevicePerseus::instance().getSequenceFromSerial(m_deviceAPI->getSampleSourceSerial().toStdString()); + + if ((m_perseusDescriptor = perseus_open(deviceSequence)) == 0) + { + qCritical("PerseusInput::openDevice: cannot open device: %s", perseus_errorstr()); + return false; + } + + int buf[32]; + m_sampleRates.clear(); + + if (perseus_get_sampling_rates(m_perseusDescriptor, buf, sizeof(buf)/sizeof(buf[0])) < 0) + { + qCritical("PerseusInput::openDevice: cannot get sampling rates: %s", perseus_errorstr()); + perseus_close(m_perseusDescriptor); + return false; + } + else + { + for (int i = 0; (i < 32) && (buf[i] != 0); i++) + { + qDebug("PerseusInput::openDevice: sample rate: %d", buf[i]); + m_sampleRates.push_back(buf[i]); + } + } + + return true; +} + +void PerseusInput::closeDevice() +{ + if (m_perseusDescriptor) + { + perseus_stop_async_input(m_perseusDescriptor); + perseus_close(m_perseusDescriptor); + } +} + diff --git a/plugins/samplesource/perseus/perseusinput.h b/plugins/samplesource/perseus/perseusinput.h new file mode 100644 index 000000000..96168a7fe --- /dev/null +++ b/plugins/samplesource/perseus/perseusinput.h @@ -0,0 +1,137 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_SAMPLESOURCE_PERSEUS_PERSEUSINPUT_H_ +#define PLUGINS_SAMPLESOURCE_PERSEUS_PERSEUSINPUT_H_ + +#include +#include "dsp/devicesamplesource.h" +#include "util/message.h" +#include "perseussettings.h" + +class DeviceSourceAPI; +class FileRecord; +class PerseusThread; +struct perseus_descr; + +class PerseusInput : public DeviceSampleSource { +public: + class MsgConfigurePerseus : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PerseusSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigurePerseus* create(const PerseusSettings& settings, bool force) + { + return new MsgConfigurePerseus(settings, force); + } + + private: + PerseusSettings m_settings; + bool m_force; + + MsgConfigurePerseus(const PerseusSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + 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) + { } + }; + + 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) + { } + }; + + PerseusInput(DeviceSourceAPI *deviceAPI); + ~PerseusInput(); + 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); + + virtual int webapiRunGet( + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage); + + virtual int webapiRun( + bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage); + +private: + DeviceSourceAPI *m_deviceAPI; + FileRecord *m_fileSink; + QString m_deviceDescription; + PerseusSettings m_settings; + bool m_running; + PerseusThread *m_perseusThread; + perseus_descr *m_perseusDescriptor; + std::vector m_sampleRates; + QMutex m_mutex; + + bool openDevice(); + void closeDevice(); + bool applySettings(const PerseusSettings& settings, bool force = false); +}; + +#endif /* PLUGINS_SAMPLESOURCE_PERSEUS_PERSEUSINPUT_H_ */ diff --git a/plugins/samplesource/perseus/perseussettings.cpp b/plugins/samplesource/perseus/perseussettings.cpp new file mode 100644 index 000000000..77a57a83f --- /dev/null +++ b/plugins/samplesource/perseus/perseussettings.cpp @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "perseussettings.h" +#include "util/simpleserializer.h" + + +PerseusSettings::PerseusSettings() +{ + resetToDefaults(); +} + +void PerseusSettings::resetToDefaults() +{ + m_centerFrequency = 7150*1000; + m_LOppmTenths = 0; + m_devSampleRateIndex = 0; + m_log2Decim = 0; + m_transverterMode = false; + m_transverterDeltaFrequency = 0; + m_adcDither = false; + m_adcPreamp = false; + m_wideBand = false; + m_attenuator = Attenuator_None; +} + +QByteArray PerseusSettings::serialize() const +{ + SimpleSerializer s(1); + + s.writeU32(1, m_devSampleRateIndex); + s.writeS32(2, m_LOppmTenths); + s.writeU32(3, m_log2Decim); + s.writeBool(4, m_transverterMode); + s.writeS64(5, m_transverterDeltaFrequency); + s.writeBool(6, m_adcDither); + s.writeBool(7, m_adcPreamp); + s.writeBool(8, m_wideBand); + s.writeS32(9, (int) m_attenuator); + + return s.final(); +} + +bool PerseusSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + int intval; + + d.readU32(1, &m_devSampleRateIndex, 0); + d.readS32(2, &m_LOppmTenths, 0); + d.readU32(3, &m_log2Decim, 0); + d.readBool(4, &m_transverterMode, false); + d.readS64(5, &m_transverterDeltaFrequency, 0); + d.readBool(6, &m_adcDither, false); + d.readBool(7, &m_adcPreamp, false); + d.readBool(8, &m_wideBand, false); + d.readS32(9, &intval, 0); + + if ((intval >= 0) && (intval < (int) Attenuator_last)) { + m_attenuator = (Attenuator) intval; + } else { + m_attenuator = Attenuator_None; + } + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + diff --git a/plugins/samplesource/perseus/perseussettings.h b/plugins/samplesource/perseus/perseussettings.h new file mode 100644 index 000000000..864bb0cec --- /dev/null +++ b/plugins/samplesource/perseus/perseussettings.h @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_SAMPLESOURCE_PERSEUS_PERSEUSSETTINGS_H_ +#define PLUGINS_SAMPLESOURCE_PERSEUS_PERSEUSSETTINGS_H_ + +#include + +struct PerseusSettings +{ + typedef enum + { + Attenuator_None, + Attenuator_10dB, + Attenuator_20dB, + Attenuator_30dB, + Attenuator_last + } Attenuator; + + quint64 m_centerFrequency; + qint32 m_LOppmTenths; + quint32 m_devSampleRateIndex; + quint32 m_log2Decim; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; + bool m_adcDither; + bool m_adcPreamp; + bool m_wideBand; + Attenuator m_attenuator; + + PerseusSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + + + +#endif /* PLUGINS_SAMPLESOURCE_PERSEUS_PERSEUSSETTINGS_H_ */