diff --git a/devices/CMakeLists.txt b/devices/CMakeLists.txt index ebd573256..d41f4de9d 100644 --- a/devices/CMakeLists.txt +++ b/devices/CMakeLists.txt @@ -28,4 +28,9 @@ else(BUILD_DEBIAN) add_subdirectory(plutosdr) endif(LIBUSB_FOUND AND LIBIIO_FOUND) + find_package(LibPerseus) + if(LIBUSB_FOUND AND LIBPERSEUS_FOUND) + add_subdirectory(perseus) + endif() + endif (BUILD_DEBIAN) diff --git a/devices/perseus/CMakeLists.txt b/devices/perseus/CMakeLists.txt new file mode 100644 index 000000000..659af597a --- /dev/null +++ b/devices/perseus/CMakeLists.txt @@ -0,0 +1,48 @@ +project(perseusdevice) + +set (CMAKE_CXX_STANDARD 11) + +set(perseusdevice_SOURCES + deviceperseus.cpp + deviceperseusscan.cpp +) + +set(perseusdevice_HEADERS + deviceperseus.h + deviceperseusscan.h +) + +if (BUILD_DEBIAN) +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBPERSEUSSRC} +) +else (BUILD_DEBIAN) +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBPERSEUS_INCLUDE_DIR} +) +endif (BUILD_DEBIAN) + +#add_definitions(${QT_DEFINITIONS}) +#add_definitions(-DQT_SHARED) + +add_library(perseusdevice SHARED + ${perseusdevice_SOURCES} +) + +if (BUILD_DEBIAN) +target_link_libraries(perseusdevice + perseus + sdrbase +) +else (BUILD_DEBIAN) +target_link_libraries(perseusdevice + ${LIBPERSEUS_LIBRARIES} + sdrbase +) +endif (BUILD_DEBIAN) + +install(TARGETS perseusdevice DESTINATION lib) diff --git a/devices/perseus/deviceperseus.cpp b/devices/perseus/deviceperseus.cpp new file mode 100644 index 000000000..0b3bbec2e --- /dev/null +++ b/devices/perseus/deviceperseus.cpp @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 "perseus-sdr.h" +#include "deviceperseus.h" + +DevicePerseus::DevicePerseus() +{ + m_nbDevices = perseus_init(); +} + +DevicePerseus::~DevicePerseus() +{ + perseus_exit(); +} + +DevicePerseus& DevicePerseus::instance() +{ + static DevicePerseus inst; + return inst; +} + diff --git a/devices/perseus/deviceperseus.h b/devices/perseus/deviceperseus.h new file mode 100644 index 000000000..1419da5fb --- /dev/null +++ b/devices/perseus/deviceperseus.h @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 DEVICES_PERSEUS_DEVICEPERSEUS_H_ +#define DEVICES_PERSEUS_DEVICEPERSEUS_H_ + +#include "deviceperseusscan.h" + +class DevicePerseus +{ +public: + static DevicePerseus& instance(); + void scan() { m_scan.scan(m_nbDevices); } + void getSerials(std::vector& serials) const { m_scan.getSerials(serials); } +protected: + DevicePerseus(); + DevicePerseus(const DevicePerseus&) : m_nbDevices(0) {} + DevicePerseus& operator=(const DevicePerseus& other __attribute__((unused))) { return *this; } + ~DevicePerseus(); +private: + int m_nbDevices; + DevicePerseusScan m_scan; +}; + + +#endif /* DEVICES_PERSEUS_DEVICEPERSEUS_H_ */ diff --git a/devices/perseus/deviceperseusscan.cpp b/devices/perseus/deviceperseusscan.cpp new file mode 100644 index 000000000..ecc532903 --- /dev/null +++ b/devices/perseus/deviceperseusscan.cpp @@ -0,0 +1,116 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 "deviceperseusscan.h" +#include "perseus-sdr.h" +#include +#include + + +void DevicePerseusScan::scan(int nbDevices) +{ + if (nbDevices == 0) { + qInfo("DevicePerseusScan::scan: no Perseus devices"); + return; + } + + perseus_descr *descr; + eeprom_prodid prodid; + + for (int deviceIndex = 0; deviceIndex < nbDevices; deviceIndex++) + { + if ((descr = perseus_open(deviceIndex)) == 0) { + qCritical("DevicePerseusScan::scan: open error: %s\n", perseus_errorstr()); + continue; + } + +// if (perseus_firmware_download(descr, 0) < 0) { +// qCritical("DevicePerseusScan::scan: firmware download error: %s", perseus_errorstr()); +// continue; +// } +// else +// { +// qInfo("DevicePerseusScan::scan: device #%d firmware downloaded", deviceIndex); +// } + + if (perseus_get_product_id(descr,&prodid) < 0) { + qCritical("DevicePerseusScan::scan: get product id error: %s", perseus_errorstr()); + perseus_close(descr); + continue; + } + else + { + uint32_t sigA = (prodid.signature[5]<<16) + prodid.signature[4]; + uint32_t sigB = (prodid.signature[3]<<16) + prodid.signature[2]; + uint32_t sigC = (prodid.signature[1]<<16) + prodid.signature[0]; + std::stringstream ss; + ss << prodid.sn << "-" << std::hex << sigA << "-" << sigB << "-" << sigC; + m_scans.push_back({ss.str(), prodid.sn, deviceIndex}); + m_serialMap[m_scans.back().m_serial] = &m_scans.back(); + perseus_close(descr); + } + } +} + +const std::string* DevicePerseusScan::getSerialAt(unsigned int index) const +{ + if (index < m_scans.size()) { + return &(m_scans[index].m_serial); + } else { + return 0; + } +} + +uint16_t DevicePerseusScan::getSerialNumberAt(unsigned int index) const +{ + if (index < m_scans.size()) { + return m_scans[index].m_serialNumber; + } else { + return 0; + } +} + +int DevicePerseusScan::getSequenceAt(unsigned int index) const +{ + if (index < m_scans.size()) { + return m_scans[index].m_sequence; + } else { + return 0; + } +} + +int DevicePerseusScan::getSequenceFromSerial(const std::string& serial) const +{ + std::map::const_iterator it = m_serialMap.find(serial); + if (it == m_serialMap.end()) { + return -1; + } else { + return ((it->second)->m_sequence); + } +} + +void DevicePerseusScan::getSerials(std::vector& serials) const +{ + std::vector::const_iterator it = m_scans.begin(); + serials.clear(); + + for (; it != m_scans.end(); ++it) { + serials.push_back(it->m_serial); + } +} + + + diff --git a/devices/perseus/deviceperseusscan.h b/devices/perseus/deviceperseusscan.h new file mode 100644 index 000000000..8eb85677a --- /dev/null +++ b/devices/perseus/deviceperseusscan.h @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 DEVICES_PERSEUS_DEVICEPERSEUSSCAN_H_ +#define DEVICES_PERSEUS_DEVICEPERSEUSSCAN_H_ + +#include +#include +#include +#include +#include + + +class DevicePerseusScan +{ +public: + struct DeviceScan + { + std::string m_serial; + uint16_t m_serialNumber; + int m_sequence; + }; + + void scan(int nbDevices); + int getNbActiveDevices() const { return m_scans.size(); } + const std::string* getSerialAt(unsigned int index) const; + uint16_t getSerialNumberAt(unsigned int index) const ; + int getSequenceAt(unsigned int index) const ; + int getSequenceFromSerial(const std::string& serial) const; + void getSerials(std::vector& serials) const; + +private: + std::vector m_scans; + std::map m_serialMap; +}; + + +#endif /* DEVICES_PERSEUS_DEVICEPERSEUSSCAN_H_ */ diff --git a/plugins/samplesource/perseus/perseusplugin.cpp b/plugins/samplesource/perseus/perseusplugin.cpp new file mode 100644 index 000000000..20042efe9 --- /dev/null +++ b/plugins/samplesource/perseus/perseusplugin.cpp @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "airspyhfplugin.h" +#include "airspyhfgui.h" + + +const PluginDescriptor PerseusPlugin::m_pluginDescriptor = { + QString("Perseus Input"), + QString("3.12.0"), + QString("(c) Edouard Griffiths, F4EXB"), + QString("https://github.com/f4exb/sdrangel"), + true, + QString("https://github.com/f4exb/sdrangel") +}; + +const QString PerseusPlugin::m_hardwareID = "Perseus"; +const QString PerseusPlugin::m_deviceTypeID = PERSEUS_DEVICE_TYPE_ID; +const int AirspyHFPlugin::m_maxDevices = 32; + +PerseusPlugin::PerseusPlugin(QObject* parent) : + QObject(parent) +{ +} + +const PluginDescriptor& PerseusPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void PerseusPlugin::initPlugin(PluginAPI* pluginAPI) +{ + pluginAPI->registerSampleSource(m_deviceTypeID, this); +} + +PluginInterface::SamplingDevices PerseusPlugin::enumSampleSources() +{ + DevicePerseus::instance().scan(); + std::vector serials; + DevicePerseus::instance().getSerials(serials); + + std::vector::const_iterator it = serials.begin(); + int i; + SamplingDevices result; + + for (i = 0; it != serials.end(); ++it, ++i) + { + QString serial_str = QString::fromLocal8Bit(it->c_str()); + QString displayedName(QString("Perseus[%1] %2").arg(i).arg(serial_str)); + + result.append(SamplingDevice(displayedName, + m_hardwareID, + m_deviceTypeID, + serial_str, + i, + PluginInterface::SamplingDevice::PhysicalDevice, + true, + 1, + 0)); + + qDebug("PerseusPlugin::enumSampleSources: enumerated PlutoSDR device #%d", i); + } + + return result; +} + +PluginInstanceGUI* PerseusPlugin::createSampleSourcePluginInstanceGUI( + const QString& sourceId, + QWidget **widget, + DeviceUISet *deviceUISet) +{ + if (sourceId == m_deviceTypeID) + { + PerseusGui* gui = new PerseusGui(deviceUISet); + *widget = gui; + return gui; + } + else + { + return 0; + } +} + +DeviceSampleSource *PerseusPlugin::createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI) +{ + if (sourceId == m_deviceTypeID) + { + PerseusInput* input = new PerseusInput(deviceAPI); + return input; + } + else + { + return 0; + } +} diff --git a/plugins/samplesource/perseus/perseusplugin.h b/plugins/samplesource/perseus/perseusplugin.h new file mode 100644 index 000000000..3d8fbea35 --- /dev/null +++ b/plugins/samplesource/perseus/perseusplugin.h @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 INCLUDE_PERSEUSPLUGIN_H +#define INCLUDE_PERSEUSPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +#define PERSEUS_DEVICE_TYPE_ID "sdrangel.samplesource.perseus" + +class PluginAPI; + +class PerseusPlugin : public QObject, public PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID PERSEUS_DEVICE_TYPE_ID) + +public: + explicit PerseusPlugin(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; + static const int m_maxDevices; + +private: + static const PluginDescriptor m_pluginDescriptor; +}; + +#endif // INCLUDE_PERSEUSPLUGIN_H