osmocom-sdr
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
August 2018
- 9 participants
- 10 discussions
Hello,
the attached patch allows to set the clock_source on uhd devices in
programs like gqrx.
Bye
1
1
Hi!
today I discovered that the gr-osmosdr package in debian unstable contains
a whooping list of 96 patches. This is due to the fact that since November
2014 there hasn't been any tagged versions in the repository.
I'd like to suggest to tag releases a bit more often.
@horizon: What about jumping to 1.0.0 right away?
Regards,
Harald
--
- Harald Welte <laforge(a)gnumonks.org> http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
(ETSI EN 300 175-7 Ch. A6)
5
5
== OsmoCon 2018 ==
OsmoCon (Osmocom Conference) 2018 is the technical conference for
Osmocom users, operators and developers!
We are happy to announce the date of OsmoCon 2018. It has been scheduled
on October 18 + 19, 2018 and will happen in Berlin, Germany.
For the second time, the Osmocom Conference brings together users,
operators and developers of the Osmocom Open Source cellular
infrastructure projects, such as OsmoBTS, OsmoBSC, OsmoSGSN, OpenGGSN
and others.
Join us for two days of presentations and discussions with the main
developers behind Open Source Mobile Communications, as well as
commercial and non-profit users of the Osmocom cellular infrastructure
software.
You can find some initial information in our wiki at
http://osmocom.org/projects/osmo-dev-con/wiki/OsmoCon2018
which will be updated as more information becomes available.
== Call for Participation ==
We're also at the same time announcing the Call for Participation and
call on everyone with experiences to share around the Osmocom member
projects to submit talks, workshops, discussions or other proposals.
You can find the CfP at https://pretalx.sysmocom.de/osmocon2018/cfp
We are particularly looking for contributions about:
* updates on features/functionality/status of individual Osmocom projects
* success stories on how Osmocom projects are deployed in practice
* migration from OsmoNITB to the post-NITB architecture
* tutorials / workshops on how to setup / analyze Osmocom projects
* statistics, reporting, operations aspects of Osmocom projects
* third-party open source utilities to be used with Osmocom projects
Looking forward to meeting many existing and new Osmocom users at OsmCon
this October!
Regards,
Harald Welte
--
- Harald Welte <laforge(a)gnumonks.org> http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
(ETSI EN 300 175-7 Ch. A6)
2
1
This builds on the work started in gr-osmosdr-gqrx arispyhf branch by
Alexandru Csete. Further adds support for all the gain stages within
the Airspy.
Kieren Rasmussen (3):
- Added support for manual gain modes of AirspyHF+ - TODO support for
AGC threshold level
- Incorrect gain clipping when setting attenuation - Verified working
with a git build of GQRX
- Split the AirspyHF+ into a separate block in GRC with more relevant
parameters exposed
README | 1 +
grc/CMakeLists.txt | 1 +
grc/gen_airspyhf_blocks.py | 281 ++++++++++++++++++++++++++++++
grc/gen_osmosdr_blocks.py | 2 +
lib/airspyhf/airspyhf_source_c.cc | 102 ++++++++++-
lib/airspyhf/airspyhf_source_c.h | 9 +
6 files changed, 392 insertions(+), 4 deletions(-)
create mode 100644 grc/gen_airspyhf_blocks.py
--
2.18.0
1
3
Re: [PATCH] gr-osmosdr Microtelecom Perseus HF receiver support (II)
by Andrea Montefusco IW0HDV 21 Aug '18
by Andrea Montefusco IW0HDV 21 Aug '18
21 Aug '18
Hi Dimitri,
>> could you please provide a signed-off patch with your latest changes ongithub and a proper commit message?
>> Feel free to add information to AUTHORS, README and the grc/gen_osmosdr_blocks.py files just like we did for other radios and ideally include a link where libperseus is hosted (I understand this is https://github.com/Microtelecom/libperseus-sdr ?).
I added the infor requested and even tested the module under GRC (non only under GQRX that is the reason I developed the patch at start).
Below you find the patch as per git command.
*am* IW0HDV
---
CMakeLists.txt | 1 +
cmake/Modules/FindLibPERSEUS.cmake | 24 ++
lib/CMakeLists.txt | 8 +
lib/airspy/airspy_source_c.cc | 5 +-
lib/config.h.in | 1 +
lib/device.cc | 8 +
lib/perseus/CMakeLists.txt | 37 +++
lib/perseus/perseus_source_c.cc | 507 +++++++++++++++++++++++++++++++++++++
lib/perseus/perseus_source_c.h | 120 +++++++++
lib/rtl/rtl_source_c.cc | 2 +-
lib/source_impl.cc | 18 +-
11 files changed, 727 insertions(+), 4 deletions(-)
create mode 100644 cmake/Modules/FindLibPERSEUS.cmake
create mode 100644 lib/perseus/CMakeLists.txt
create mode 100644 lib/perseus/perseus_source_c.cc
create mode 100644 lib/perseus/perseus_source_c.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 296456d..94acd4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -173,6 +173,7 @@ find_package(Volk)
find_package(LibbladeRF)
find_package(SoapySDR NO_MODULE)
find_package(LibFreeSRP)
+find_package(LibPERSEUS)
find_package(Doxygen)
if(NOT GNURADIO_RUNTIME_FOUND)
diff --git a/cmake/Modules/FindLibPERSEUS.cmake b/cmake/Modules/FindLibPERSEUS.cmake
new file mode 100644
index 0000000..5477327
--- /dev/null
+++ b/cmake/Modules/FindLibPERSEUS.cmake
@@ -0,0 +1,24 @@
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(PC_LIBPERSEUS libperseus-sdr)
+
+FIND_PATH(
+ LIBPERSEUS_INCLUDE_DIRS
+ NAMES perseus-sdr.h
+ HINTS $ENV{LIBPERSEUS_DIR}/include
+ ${PC_LIBPERSEUS_INCLUDEDIR}
+ PATHS /usr/local/include
+ /usr/include
+)
+
+FIND_LIBRARY(
+ LIBPERSEUS_LIBRARIES
+ NAMES perseus-sdr
+ HINTS $ENV{LIBPERSEUS_DIR}/lib
+ ${PC_LIBPERSEUS_LIBDIR}
+ PATHS /usr/local/lib
+ /usr/lib
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBPERSEUS DEFAULT_MSG LIBPERSEUS_LIBRARIES LIBPERSEUS_INCLUDE_DIRS)
+MARK_AS_ADVANCED(LIBPERSEUS_LIBRARIES LIBPERSEUS_INCLUDE_DIRS)
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index c05b8d9..f555816 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -249,6 +249,14 @@ GR_INCLUDE_SUBDIRECTORY(freesrp)
endif(ENABLE_FREESRP)
########################################################################
+# Setup PERSEUS component
+########################################################################
+GR_REGISTER_COMPONENT("Microtelecom Perseus Receiver" ENABLE_PERSEUS LIBPERSEUS_FOUND)
+if(ENABLE_PERSEUS)
+GR_INCLUDE_SUBDIRECTORY(perseus)
+endif(ENABLE_PERSEUS)
+
+########################################################################
# Setup configuration file
########################################################################
ADD_DEFINITIONS(-DHAVE_CONFIG_H=1)
diff --git a/lib/airspy/airspy_source_c.cc b/lib/airspy/airspy_source_c.cc
index 50150e5..02fc6ab 100644
--- a/lib/airspy/airspy_source_c.cc
+++ b/lib/airspy/airspy_source_c.cc
@@ -350,9 +350,10 @@ osmosdr::meta_range_t airspy_source_c::get_sample_rates()
{
osmosdr::meta_range_t range;
- for (size_t i = 0; i < _sample_rates.size(); i++)
+ for (size_t i = 0; i < _sample_rates.size(); i++) {
+ std::cerr << "SR: [" << i << "]: " << _sample_rates[i].first << std::endl;
range += osmosdr::range_t( _sample_rates[i].first );
-
+ }
return range;
}
diff --git a/lib/config.h.in b/lib/config.h.in
index 42e72f1..dac7e39 100644
--- a/lib/config.h.in
+++ b/lib/config.h.in
@@ -19,6 +19,7 @@
#cmakedefine ENABLE_SOAPY
#cmakedefine ENABLE_REDPITAYA
#cmakedefine ENABLE_FREESRP
+#cmakedefine ENABLE_PERSEUS
//provide NAN define for MSVC older than VC12
#if defined(_MSC_VER) && (_MSC_VER < 1800)
diff --git a/lib/device.cc b/lib/device.cc
index 025a22b..df0d734 100644
--- a/lib/device.cc
+++ b/lib/device.cc
@@ -90,6 +90,10 @@
#include <freesrp_source_c.h>
#endif
+#ifdef ENABLE_PERSEUS
+#include <perseus_source_c.h>
+#endif
+
#include "arg_helpers.h"
using namespace osmosdr;
@@ -194,6 +198,10 @@ devices_t device::find(const device_t &hint)
BOOST_FOREACH( std::string dev, soapy_source_c::get_devices() )
devices.push_back( device_t(dev) );
#endif
+#ifdef ENABLE_PERSEUS
+ BOOST_FOREACH( std::string dev, perseus_source_c::get_devices() )
+ devices.push_back( device_t(dev) );
+#endif
/* software-only sources should be appended at the very end,
* hopefully resulting in hardware sources to be shown first
diff --git a/lib/perseus/CMakeLists.txt b/lib/perseus/CMakeLists.txt
new file mode 100644
index 0000000..f45a10d
--- /dev/null
+++ b/lib/perseus/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright 2017 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+########################################################################
+# This file included, use CMake directory variables
+########################################################################
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${LIBPERSEUS_INCLUDE_DIRS}
+)
+
+set(perseus_srcs
+ ${CMAKE_CURRENT_SOURCE_DIR}/perseus_source_c.cc
+)
+
+########################################################################
+# Append gnuradio-osmosdr library sources
+########################################################################
+list(APPEND gr_osmosdr_srcs ${perseus_srcs})
+list(APPEND gr_osmosdr_libs ${LIBPERSEUS_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES})
diff --git a/lib/perseus/perseus_source_c.cc b/lib/perseus/perseus_source_c.cc
new file mode 100644
index 0000000..0720da4
--- /dev/null
+++ b/lib/perseus/perseus_source_c.cc
@@ -0,0 +1,507 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2018 Andrea Montefusco IW0HDV
+ *
+ * GNU Radio 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; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * config.h is generated by configure. It contains the results
+ * of probing for features, options etc. It should be the first
+ * file included in your .cc file.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdexcept>
+#include <iostream>
+#include <algorithm>
+
+#include <boost/assign.hpp>
+#include <boost/format.hpp>
+#include <boost/detail/endian.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <gnuradio/io_signature.h>
+
+#include "perseus_source_c.h"
+#include "arg_helpers.h"
+
+
+
+using namespace boost::assign;
+
+#define PERSEUS_FORMAT_ERROR(ret, msg) \
+ boost::str( boost::format(msg " (%1%)") % ret )
+
+#define PERSEUS_THROW_ON_ERROR(ret, msg) \
+ if ( ret != PERSEUS_NOERROR ) \
+ { \
+ throw std::runtime_error( PERSEUS_FORMAT_ERROR(ret, msg) ); \
+ }
+
+#define PERSEUS_FUNC_STR(func, arg) \
+ boost::str(boost::format(func "(%1%)") % arg) + " has failed"
+
+perseus_source_c_sptr make_perseus_source_c (const std::string & args)
+{
+ return gnuradio::get_initial_sptr(new perseus_source_c (args));
+}
+
+/*
+ * Specify constraints on number of input and output streams.
+ * This info is used to construct the input and output signatures
+ * (2nd & 3rd args to gr::block's constructor). The input and
+ * output signatures are used by the runtime system to
+ * check that a valid number and type of inputs and outputs
+ * are connected to this block. In this case, we accept
+ * only 0 input and 1 output.
+ */
+static const int MIN_IN = 0; // mininum number of input streams
+static const int MAX_IN = 0; // maximum number of input streams
+static const int MIN_OUT = 1; // minimum number of output streams
+static const int MAX_OUT = 1; // maximum number of output streams
+
+/*
+ * The private constructor
+ */
+perseus_source_c::perseus_source_c (const std::string &args)
+ : gr::sync_block ("perseus_source_c",
+ gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)),
+ gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))),
+ _dev(NULL),
+ _sample_rate(0),
+ _center_freq(0),
+ _freq_corr(0),
+ _frun(false),
+ _cnt(0)
+{
+ //int ret;
+
+ dict_t dict = params_to_dict(args);
+
+ _dev = NULL;
+
+ // Set debug info dumped to stderr to the maximum verbose level
+ perseus_set_debug(3);
+
+ //fprintf (stderr, "Revision: %s\n", git_revision);
+ //fprintf (stderr, "SAMPLE RATE: %d\n", sr);
+ //fprintf (stderr, "NBUF: %d BUF SIZE: %d TOTAL BUFFER LENGTH: %d\n", nb, bs, nb*bs);
+
+ // Check how many Perseus receivers are connected to the system
+ int num_perseus = perseus_init();
+ std::cerr << "## Microtelecom Perseus ctor: " << num_perseus << " Perseus receivers found." << std::endl;
+
+ if (num_perseus==0) {
+ perseus_exit();
+ PERSEUS_THROW_ON_ERROR(PERSEUS_DEVNOTFOUND, "No Perseus receivers detected");
+ }
+ // Open the first one...
+ if ((_dev = perseus_open(0)) == NULL) {
+ PERSEUS_THROW_ON_ERROR(PERSEUS_DEVNOTFOUND, "Unable to open Perseus device");
+ }
+ // Download the standard firmware to the unit
+ std::cerr << "Downloading firmware..." << std::endl;
+ if (int rc = perseus_firmware_download(_dev,NULL)<0) {
+ PERSEUS_THROW_ON_ERROR (rc, "firmware download error");
+ }
+
+ // Dump some information about the receiver (S/N and HW rev)
+ int flag;
+ perseus_is_preserie(_dev, &flag);
+ if (flag != 0)
+ fprintf(stderr, "The device is a preserie unit");
+ else {
+ eeprom_prodid prodid;
+ if (perseus_get_product_id(_dev,&prodid)<0)
+ fprintf(stderr, "get product id error: %s", perseus_errorstr());
+ else
+ fprintf(stderr, "Receiver S/N: %05d-%02hX%02hX-%02hX%02hX-%02hX%02hX - HW Release:%hd.%hd\n",
+ (uint16_t) prodid.sn,
+ (uint16_t) prodid.signature[5],
+ (uint16_t) prodid.signature[4],
+ (uint16_t) prodid.signature[3],
+ (uint16_t) prodid.signature[2],
+ (uint16_t) prodid.signature[1],
+ (uint16_t) prodid.signature[0],
+ (uint16_t) prodid.hwrel,
+ (uint16_t) prodid.hwver);
+ }
+ // Printing all sampling rates available .....
+ {
+ int buf[BUFSIZ];
+
+ if (perseus_get_sampling_rates (_dev, buf, sizeof(buf)/sizeof(buf[0])) < 0) {
+ fprintf(stderr, "get sampling rates error: %s\n", perseus_errorstr());
+ } else {
+ int i = 0;
+ while (buf[i]) {
+ fprintf(stderr, "#%d: sample rate: %d\n", i, buf[i]);
+
+ _sample_rates.push_back( std::pair<double, uint32_t>( buf[i], i ) );
+ i++;
+ }
+ /* since they may (and will) give us an unsorted array we have to sort it here
+ * to play nice with the monotonic requirement of meta-range later on */
+ std::sort(_sample_rates.begin(), _sample_rates.end());
+
+ for (size_t i = 0; i < _sample_rates.size(); i++)
+ std::cerr << boost::format("%gM ") % (_sample_rates[i].first / 1e6);
+
+ std::cerr << std::endl;
+ }
+ }
+ // Configure the receiver for 2 MS/s operations
+ fprintf(stderr, "Configuring FPGA...\n");
+ if (int ret = perseus_set_sampling_rate(_dev, 96000) < 0) { // specify the sampling rate value in Samples/second
+ std::cerr << "fpga configuration error: " << perseus_errorstr() << std::endl;
+ PERSEUS_THROW_ON_ERROR(ret, "Perseus fpga configuration error");
+ }
+
+ perseus_set_attenuator_in_db(_dev, PERSEUS_ATT_0DB);
+ // Enable ADC Dither, Disable ADC Preamp
+ perseus_set_adc(_dev, true, false);
+ // set the NCO frequency in the middle of the range allowed
+ set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 );
+ set_sample_rate( get_sample_rates().start() );
+
+ _fifo = new boost::circular_buffer<gr_complex>(5000000);
+ if (!_fifo) {
+ throw std::runtime_error( std::string(__FUNCTION__) + " " +
+ "Failed to allocate a sample FIFO!" );
+ }
+}
+
+/*
+ * Our virtual destructor.
+ */
+perseus_source_c::~perseus_source_c ()
+{
+ if (_dev) {
+ if (_frun) stop();
+ int ret = perseus_close(_dev);
+ if ( ret != PERSEUS_NOERROR ) {
+ std::cerr << PERSEUS_FORMAT_ERROR(ret, "Failed to close Perseus") << std::endl;
+ } else
+ _dev = NULL;
+ }
+ perseus_exit();
+
+ if (_fifo) {
+ delete _fifo;
+ _fifo = NULL;
+ }
+}
+
+
+typedef union {
+ struct {
+ int32_t i;
+ int32_t q;
+ } __attribute__((__packed__)) iq;
+ struct {
+ uint8_t i1;
+ uint8_t i2;
+ uint8_t i3;
+ uint8_t i4;
+ uint8_t q1;
+ uint8_t q2;
+ uint8_t q3;
+ uint8_t q4;
+ } __attribute__((__packed__)) ;
+} iq_sample;
+
+
+int perseus_source_c::perseus_rx_callback(void *buf, int buf_size)
+{
+ size_t i, n_avail, to_copy, num_samples;
+
+ uint8_t *samplebuf = (uint8_t*)buf;
+
+ num_samples = buf_size/6;
+
+ if (buf_size % 6)
+ std::cerr << "FATAL !!!!!!! not on boundary" << std::endl;
+
+ iq_sample s;
+
+ _fifo_lock.lock();
+
+ n_avail = _fifo->capacity() - _fifo->size();
+ to_copy = (n_avail < num_samples ? n_avail : num_samples);
+
+ for (i = 0; i < to_copy; i++ ) {
+
+ s.i1 = s.q1 = 0;
+ s.i2 = *samplebuf++;
+ s.i3 = *samplebuf++;
+ s.i4 = *samplebuf++;
+ s.q2 = *samplebuf++;
+ s.q3 = *samplebuf++;
+ s.q4 = *samplebuf++;
+
+ // convert 24 bit two's complements integers to float in [-1.0 - +1.0] range
+
+ /* Push sample to the fifo */
+ _fifo->push_back( gr_complex( (float)(s.iq.i) / (INT_MAX - 256), (float)(s.iq.q) / (INT_MAX - 256) ) );
+
+ }
+ // keep a counter of processed bytes
+ _cnt += buf_size;
+
+ _fifo_lock.unlock();
+
+ /* We have made some new samples available to the consumer in work() */
+ if (to_copy) {
+ //std::cerr << "+" << std::flush;
+ _samp_avail.notify_one();
+ }
+
+ /* Indicate overrun, if necessary */
+ if (to_copy < num_samples)
+ std::cerr << "O" << std::flush;
+
+ return 0; // TODO: return -1 on error/stop
+}
+
+// static method used as callback from the libperseus-sdr library
+int perseus_source_c::_perseus_rx_callback(void *buf, int buf_size, void *extra)
+{
+ perseus_source_c *obj = (perseus_source_c *)extra;
+
+ return obj->perseus_rx_callback((float *)buf, buf_size);
+
+ return 0;
+}
+
+
+bool perseus_source_c::start()
+{
+ int ret;
+
+ if ( ! _dev )
+ return false;
+
+ std::cerr << "***** START COUNTER: " << _cnt
+ << " mod 6 " << (_cnt % 6) << std::endl;
+
+ _frun = true;
+
+ // in order to guarantee samples stream synchronization
+ // re-set the sample rate each time the stream is started
+ set_sample_rate( get_sample_rate() );
+
+ ret = perseus_start_async_input(_dev,
+ 6 * 1024 * 2 /* buffer size */,
+ perseus_source_c::_perseus_rx_callback,
+ (void *)this);
+ if (ret != PERSEUS_NOERROR) {
+ std::cerr << "Failed to start RX streaming ("
+ << ret << ")" << std::endl;
+ return false;
+ } else
+ return true;
+}
+
+bool perseus_source_c::stop()
+{
+ if ( ! _dev )
+ return false;
+
+ _frun = false;
+
+ std::cerr << "***** STOP COUNTER: " << _cnt
+ << " mod 6 " << (_cnt % 6) << std::endl;
+
+ int ret = perseus_stop_async_input(_dev);
+
+ if ( ret != PERSEUS_NOERROR ) {
+ std::cerr << "Failed to stop RX streaming (" << ret << ")" << std::endl;
+ return false;
+ } else
+ return true;
+}
+
+int perseus_source_c::work( int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items )
+{
+ gr_complex *out = (gr_complex *)output_items[0];
+
+ if ( _frun == false ) return WORK_DONE;
+
+ boost::unique_lock<boost::mutex> lock(_fifo_lock);
+
+ /* Wait until we have the requested number of samples */
+ int n_samples_avail = _fifo->size();
+
+ while (n_samples_avail < noutput_items) {
+ _samp_avail.wait(lock);
+ n_samples_avail = _fifo->size();
+ }
+
+ for(int i = 0; i < noutput_items; ++i) {
+ out[i] = _fifo->at(0);
+ _fifo->pop_front();
+ }
+
+ return noutput_items;
+}
+
+std::vector<std::string> perseus_source_c::get_devices()
+{
+ std::vector<std::string> devices;
+ std::string label;
+
+ std::string args = "perseus=0,label='Perseus'";
+ devices.push_back( args );
+
+ return devices;
+}
+
+size_t perseus_source_c::get_num_channels()
+{
+ return 1;
+}
+
+osmosdr::meta_range_t perseus_source_c::get_sample_rates()
+{
+ osmosdr::meta_range_t range;
+
+ for (size_t i = 0; i < _sample_rates.size(); i++) {
+ range += osmosdr::range_t( _sample_rates[i].first );
+ std::cerr << "SR: " << i << " : ("
+ << _sample_rates[i].first << ")" << std::endl;
+ }
+ return range;
+}
+
+double perseus_source_c::set_sample_rate( double rate )
+{
+ int ret;
+ if ((ret = perseus_set_sampling_rate(_dev, rate)) < 0) {
+ PERSEUS_THROW_ON_ERROR(ret, "Unable to set sample rate.");
+ } else
+ _sample_rate = rate;
+
+ return get_sample_rate();
+}
+
+double perseus_source_c::get_sample_rate()
+{
+ return _sample_rate;
+}
+
+osmosdr::freq_range_t perseus_source_c::get_freq_range( size_t chan )
+{
+ osmosdr::freq_range_t range;
+
+ range += osmosdr::range_t( PERSEUS_DDC_FREQ_MIN, PERSEUS_DDC_FREQ_MAX );
+
+ return range;
+}
+
+double perseus_source_c::set_center_freq( double freq, size_t chan )
+{
+ int ret;
+
+ if (_dev) {
+ ret =
+ perseus_set_ddc_center_freq(_dev,
+ (uint64_t)(freq * (1.0 + (_freq_corr * 10e-6))),
+ 1);
+ if ( ret == PERSEUS_NOERROR ) {
+ _center_freq = freq;
+ } else {
+ PERSEUS_THROW_ON_ERROR( ret, PERSEUS_FUNC_STR( "perseus_set_ddc_center_freq", freq ) )
+ }
+ }
+
+ return get_center_freq( chan );
+}
+
+double perseus_source_c::get_center_freq( size_t chan )
+{
+ return _center_freq;
+}
+
+double perseus_source_c::set_freq_corr( double ppm, size_t chan )
+{
+ return _freq_corr = ppm;
+}
+
+double perseus_source_c::get_freq_corr( size_t chan )
+{
+ return _freq_corr;
+}
+
+std::vector<std::string> perseus_source_c::get_gain_names( size_t chan )
+{
+ return {};
+}
+
+osmosdr::gain_range_t perseus_source_c::get_gain_range( size_t chan )
+{
+ return osmosdr::gain_range_t();
+}
+
+osmosdr::gain_range_t perseus_source_c::get_gain_range( const std::string & name, size_t chan )
+{
+ return osmosdr::gain_range_t();
+}
+
+
+double perseus_source_c::set_gain( double gain, size_t chan )
+{
+ return gain;
+}
+
+double perseus_source_c::set_gain( double gain, const std::string & name, size_t chan)
+{
+ return gain;
+}
+
+double perseus_source_c::get_gain( size_t chan )
+{
+ return 0.0;
+}
+
+double perseus_source_c::get_gain( const std::string & name, size_t chan )
+{
+ return 0.0;
+}
+
+std::vector< std::string > perseus_source_c::get_antennas( size_t chan )
+{
+ std::vector< std::string > antennas;
+
+ antennas += get_antenna( chan );
+
+ return antennas;
+}
+
+std::string perseus_source_c::set_antenna( const std::string & antenna, size_t chan )
+{
+ return get_antenna( chan );
+}
+
+std::string perseus_source_c::get_antenna( size_t chan )
+{
+ return "RX";
+}
diff --git a/lib/perseus/perseus_source_c.h b/lib/perseus/perseus_source_c.h
new file mode 100644
index 0000000..9eda23d
--- /dev/null
+++ b/lib/perseus/perseus_source_c.h
@@ -0,0 +1,120 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Dimitri Stolnikov <horiz0n(a)gmx.net>
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio 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; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef INCLUDED_PERSEUS_SOURCE_C_H
+#define INCLUDED_PERSEUS_SOURCE_C_H
+
+#include <boost/circular_buffer.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+
+#include <gnuradio/sync_block.h>
+
+#include "source_iface.h"
+#include <perseus-sdr.h>
+
+class perseus_source_c;
+
+typedef boost::shared_ptr<perseus_source_c> perseus_source_c_sptr;
+
+/*!
+ * \brief Return a shared_ptr to a new instance of perseus_source_c.
+ *
+ * To avoid accidental use of raw pointers, perseus_source_c's
+ * constructor is private. make_perseus_source_c is the public
+ * interface for creating new instances.
+ */
+perseus_source_c_sptr make_perseus_source_c (const std::string & args = "");
+
+/*!
+ * \brief Provides a stream of complex samples.
+ * \ingroup block
+ */
+class perseus_source_c :
+ public gr::sync_block,
+ public source_iface
+{
+private:
+ // The friend declaration allows make_perseus_source_c to
+ // access the private constructor.
+
+ friend perseus_source_c_sptr make_perseus_source_c (const std::string & args);
+
+ perseus_source_c (const std::string & args);
+
+public:
+ ~perseus_source_c ();
+
+ bool start();
+ bool stop();
+
+ int work( int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items );
+
+ static std::vector< std::string > get_devices();
+
+ size_t get_num_channels( void );
+
+ osmosdr::meta_range_t get_sample_rates( void );
+ double set_sample_rate( double rate );
+ double get_sample_rate( void );
+
+ osmosdr::freq_range_t get_freq_range( size_t chan = 0 );
+ double set_center_freq( double freq, size_t chan = 0 );
+ double get_center_freq( size_t chan = 0 );
+ double set_freq_corr( double ppm, size_t chan = 0 );
+ double get_freq_corr( size_t chan = 0 );
+
+ std::vector<std::string> get_gain_names( size_t chan = 0 );
+ osmosdr::gain_range_t get_gain_range( size_t chan = 0 );
+ osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 );
+ double set_gain( double gain, size_t chan = 0 );
+ double set_gain( double gain, const std::string & name, size_t chan = 0 );
+ double get_gain( size_t chan = 0 );
+ double get_gain( const std::string & name, size_t chan = 0 );
+
+ std::vector< std::string > get_antennas( size_t chan = 0 );
+ std::string set_antenna( const std::string & antenna, size_t chan = 0 );
+ std::string get_antenna( size_t chan = 0 );
+
+
+private:
+ static int _perseus_rx_callback(void *buf, int buf_size, void *extra);
+
+ int perseus_rx_callback(void *samples, int sample_count);
+
+ perseus_descr *_dev;
+
+ boost::circular_buffer<gr_complex> *_fifo;
+ boost::mutex _fifo_lock;
+ boost::condition_variable _samp_avail;
+
+ std::vector< std::pair<double, uint32_t> > _sample_rates;
+ double _sample_rate;
+ double _center_freq;
+ double _freq_corr;
+
+ bool _frun;
+ int _cnt;
+};
+
+#endif /* INCLUDED_PERSEUS_SOURCE_C_H */
diff --git a/lib/rtl/rtl_source_c.cc b/lib/rtl/rtl_source_c.cc
index a371464..eb7042e 100644
--- a/lib/rtl/rtl_source_c.cc
+++ b/lib/rtl/rtl_source_c.cc
@@ -221,7 +221,7 @@ rtl_source_c::rtl_source_c (const std::string &args)
throw std::runtime_error("Failed to enable offset tuning.");
}
- ret = rtlsdr_set_bias_tee(_dev, bias_tee);
+// ret = rtlsdr_set_bias_tee(_dev, bias_tee);
if (ret < 0)
throw std::runtime_error("Failed to set bias tee.");
diff --git a/lib/source_impl.cc b/lib/source_impl.cc
index a28f314..ead4ef7 100644
--- a/lib/source_impl.cc
+++ b/lib/source_impl.cc
@@ -92,6 +92,9 @@
#include <freesrp_source_c.h>
#endif
+#ifdef ENABLE_PERSEUS
+#include <perseus_source_c.h>
+#endif
#include "arg_helpers.h"
#include "source_impl.h"
@@ -171,6 +174,9 @@ source_impl::source_impl( const std::string &args )
#ifdef ENABLE_FREESRP
dev_types.push_back("freesrp");
#endif
+#ifdef ENABLE_PERSEUS
+ dev_types.push_back("perseus");
+#endif
std::cerr << "gr-osmosdr "
<< GR_OSMOSDR_VERSION << " (" << GR_OSMOSDR_LIBVER << ") "
<< "gnuradio " << gr::version() << std::endl;
@@ -252,7 +258,10 @@ source_impl::source_impl( const std::string &args )
BOOST_FOREACH( std::string dev, freesrp_source_c::get_devices() )
dev_list.push_back( dev );
#endif
-
+#ifdef ENABLE_PERSEUS
+ BOOST_FOREACH( std::string dev, perseus_source_c::get_devices() )
+ dev_list.push_back( dev );
+#endif
// std::cerr << std::endl;
// BOOST_FOREACH( std::string dev, dev_list )
// std::cerr << "'" << dev << "'" << std::endl;
@@ -383,6 +392,13 @@ source_impl::source_impl( const std::string &args )
}
#endif
+#ifdef ENABLE_PERSEUS
+ if ( dict.count("perseus") ) {
+ perseus_source_c_sptr src = make_perseus_source_c( arg );
+ block = src; iface = src.get();
+ }
+#endif
+
if ( iface != NULL && long(block.get()) != 0 ) {
_devs.push_back( iface );
--
1.9.1
>From 1b6cf50a7a6074754717b0270757931c379561bc Mon Sep 17 00:00:00 2001
From: Andrea Montefusco IW0HDV <andrew(a)montefusco.com>
Date: Thu, 1 Feb 2018 17:33:39 +0100
Subject: [PATCH 2/6] More hardware controls added (attenuator, ADC preamp and
dither, preselector)
---
lib/perseus/perseus_source_c.cc | 136 ++++++++++++++++++++++++++++++++++++----
lib/perseus/perseus_source_c.h | 19 +++++-
2 files changed, 142 insertions(+), 13 deletions(-)
diff --git a/lib/perseus/perseus_source_c.cc b/lib/perseus/perseus_source_c.cc
index 0720da4..89674b1 100644
--- a/lib/perseus/perseus_source_c.cc
+++ b/lib/perseus/perseus_source_c.cc
@@ -89,7 +89,11 @@ perseus_source_c::perseus_source_c (const std::string &args)
_center_freq(0),
_freq_corr(0),
_frun(false),
- _cnt(0)
+ _cnt(0),
+ _att_value(0),
+ _adc_preamp(false),
+ _adc_dither(false),
+ _preselector(false)
{
//int ret;
@@ -174,9 +178,9 @@ perseus_source_c::perseus_source_c (const std::string &args)
PERSEUS_THROW_ON_ERROR(ret, "Perseus fpga configuration error");
}
- perseus_set_attenuator_in_db(_dev, PERSEUS_ATT_0DB);
+ perseus_set_attenuator_in_db(_dev, _att_value);
// Enable ADC Dither, Disable ADC Preamp
- perseus_set_adc(_dev, true, false);
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
// set the NCO frequency in the middle of the range allowed
set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 );
set_sample_rate( get_sample_rates().start() );
@@ -425,7 +429,7 @@ double perseus_source_c::set_center_freq( double freq, size_t chan )
ret =
perseus_set_ddc_center_freq(_dev,
(uint64_t)(freq * (1.0 + (_freq_corr * 10e-6))),
- 1);
+ _preselector == true ? 1:0);
if ( ret == PERSEUS_NOERROR ) {
_center_freq = freq;
} else {
@@ -453,55 +457,165 @@ double perseus_source_c::get_freq_corr( size_t chan )
std::vector<std::string> perseus_source_c::get_gain_names( size_t chan )
{
- return {};
+ std::vector< std::string > names;
+
+ names += "Attenuator";
+ names += "ADC preamp";
+ names += "ADC dither";
+
+ return names;
}
+//
+// FIXME
+//
osmosdr::gain_range_t perseus_source_c::get_gain_range( size_t chan )
{
- return osmosdr::gain_range_t();
+ return get_gain_range( "Attenuator", chan );
}
osmosdr::gain_range_t perseus_source_c::get_gain_range( const std::string & name, size_t chan )
{
+ if ( "Attenuator" == name ) {
+ return osmosdr::gain_range_t( -30, 0, 10 );
+ }
+ if ( "ADC preamp" == name ) {
+ return osmosdr::gain_range_t( 0, 6, 6 );
+ }
+ if ( "ADC dither" == name ) {
+ return osmosdr::gain_range_t( 0, 1, 1 );
+ }
+
return osmosdr::gain_range_t();
}
-double perseus_source_c::set_gain( double gain, size_t chan )
+double perseus_source_c::set_attenuator( double gain, size_t chan )
{
+ int ret;
+
+ gain = - gain;
+ if (_dev && _att_value != gain) {
+ ret = perseus_set_attenuator_in_db (_dev, gain);
+
+ if ( PERSEUS_NOERROR == ret ) {
+ _att_value = gain;
+ } else {
+ std::cerr << "ERROR: perseus_set_attenuator_in_db: " << gain << std::endl;
+ }
+ }
+
+ return _att_value;
+}
+
+double perseus_source_c::set_adc_preamp( double gain, size_t chan )
+{
+ std::cerr << "set_adc_preamp: " << gain << std::endl;
+
+ if (_dev) {
+ _adc_preamp = (gain != 0. ? true : false);
+ int ret =
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ if ( PERSEUS_NOERROR != ret ) {
+ std::cerr << "ERROR: perseus_set_adc" << ret << std::endl;
+ }
+ }
return gain;
}
-double perseus_source_c::set_gain( double gain, const std::string & name, size_t chan)
+double perseus_source_c::set_adc_dither( double gain, size_t chan )
{
+ std::cerr << "set_adc_dither: " << gain << std::endl;
+
+ if (_dev) {
+ _adc_dither = (gain != 0. ? true : false);
+ int ret =
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ if ( PERSEUS_NOERROR != ret ) {
+ std::cerr << "ERROR: perseus_set_adc" << ret << std::endl;
+ }
+ }
return gain;
}
-double perseus_source_c::get_gain( size_t chan )
+double perseus_source_c::get_attenuator( size_t chan )
{
- return 0.0;
+ return _att_value;
}
+double perseus_source_c::get_adc_preamp(size_t chan )
+{
+ double v = _adc_preamp == true ? 6. : 0.;
+ std::cerr << "get_adc_preamp: " << _adc_preamp << " value" << v << std::endl;
+ return v;
+}
+
+double perseus_source_c::get_adc_dither(size_t chan )
+{
+ double v = _adc_dither == true ? 1. : 0.;
+ std::cerr << "get_adc_dither: " << _adc_dither << " value" << v << std::endl;
+ return v;
+}
+
+
+double perseus_source_c::set_gain( double gain, const std::string & name, size_t chan)
+{
+ if ( "Attenuator" == name ) {
+ return set_attenuator( gain, chan );
+ }
+ if ( "ADC preamp" == name ) {
+ return set_adc_preamp( gain, chan );
+ }
+ if ( "ADC dither" == name ) {
+ return set_adc_dither( gain, chan );
+ }
+ return gain;
+}
+
+
double perseus_source_c::get_gain( const std::string & name, size_t chan )
{
+ if ( "Attenuator" == name ) {
+ return get_attenuator( chan );
+ }
+ if ( "ADC preamp" == name ) {
+ return get_adc_preamp( chan );
+ }
+ if ( "ADC dither" == name ) {
+ return get_adc_dither( chan );
+ }
return 0.0;
}
+
+
std::vector< std::string > perseus_source_c::get_antennas( size_t chan )
{
std::vector< std::string > antennas;
- antennas += get_antenna( chan );
+ antennas += "RX";
+ antennas += "RX+PRESELECTOR";
return antennas;
}
std::string perseus_source_c::set_antenna( const std::string & antenna, size_t chan )
{
+ if ( antenna == "RX" ) {
+ _preselector = false;
+ set_center_freq( get_center_freq() );
+ return "RX";
+ }
+ if ( antenna == "RX+PRESELECTOR" ) {
+ _preselector = true;
+ set_center_freq( get_center_freq() );
+ return "RX+PRESELECTOR";
+ }
return get_antenna( chan );
}
std::string perseus_source_c::get_antenna( size_t chan )
{
+ std::cerr << "perseus_source_c::get_antenna: " << chan << std::endl;
return "RX";
}
diff --git a/lib/perseus/perseus_source_c.h b/lib/perseus/perseus_source_c.h
index 9eda23d..934ff2b 100644
--- a/lib/perseus/perseus_source_c.h
+++ b/lib/perseus/perseus_source_c.h
@@ -87,9 +87,20 @@ public:
std::vector<std::string> get_gain_names( size_t chan = 0 );
osmosdr::gain_range_t get_gain_range( size_t chan = 0 );
osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 );
- double set_gain( double gain, size_t chan = 0 );
+
+ double set_gain( double gain, size_t chan = 0 ) {return gain; }
+ double get_gain( size_t chan = 0 ) {return _att_value; }
+
+ double set_attenuator( double gain, size_t chan = 0 );
+ double get_attenuator( size_t chan = 0 );
+
+ double set_adc_preamp( double gain, size_t chan = 0 );
+ double get_adc_preamp( size_t chan = 0 );
+
+ double set_adc_dither( double gain, size_t chan = 0 );
+ double get_adc_dither( size_t chan = 0 );
+
double set_gain( double gain, const std::string & name, size_t chan = 0 );
- double get_gain( size_t chan = 0 );
double get_gain( const std::string & name, size_t chan = 0 );
std::vector< std::string > get_antennas( size_t chan = 0 );
@@ -115,6 +126,10 @@ private:
bool _frun;
int _cnt;
+ double _att_value;
+ bool _adc_preamp;
+ bool _adc_dither;
+ bool _preselector;
};
#endif /* INCLUDED_PERSEUS_SOURCE_C_H */
--
1.9.1
>From ff520c9d98d0bdeb9cf59cc092a08d54ced76af1 Mon Sep 17 00:00:00 2001
From: Andrea Montefusco IW0HDV <andrew(a)montefusco.com>
Date: Sat, 3 Feb 2018 08:55:32 +0100
Subject: [PATCH 3/6] files not enclosed in patch restored
---
lib/airspy/airspy_source_c.cc | 5 ++---
lib/rtl/rtl_source_c.cc | 2 +-
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/lib/airspy/airspy_source_c.cc b/lib/airspy/airspy_source_c.cc
index 02fc6ab..50150e5 100644
--- a/lib/airspy/airspy_source_c.cc
+++ b/lib/airspy/airspy_source_c.cc
@@ -350,10 +350,9 @@ osmosdr::meta_range_t airspy_source_c::get_sample_rates()
{
osmosdr::meta_range_t range;
- for (size_t i = 0; i < _sample_rates.size(); i++) {
- std::cerr << "SR: [" << i << "]: " << _sample_rates[i].first << std::endl;
+ for (size_t i = 0; i < _sample_rates.size(); i++)
range += osmosdr::range_t( _sample_rates[i].first );
- }
+
return range;
}
diff --git a/lib/rtl/rtl_source_c.cc b/lib/rtl/rtl_source_c.cc
index eb7042e..a371464 100644
--- a/lib/rtl/rtl_source_c.cc
+++ b/lib/rtl/rtl_source_c.cc
@@ -221,7 +221,7 @@ rtl_source_c::rtl_source_c (const std::string &args)
throw std::runtime_error("Failed to enable offset tuning.");
}
-// ret = rtlsdr_set_bias_tee(_dev, bias_tee);
+ ret = rtlsdr_set_bias_tee(_dev, bias_tee);
if (ret < 0)
throw std::runtime_error("Failed to set bias tee.");
--
1.9.1
>From a195b8a7eb328ed7c0b31a1e4aa077e11789f648 Mon Sep 17 00:00:00 2001
From: Andrea Montefusco IW0HDV <andrew(a)montefusco.com>
Date: Sat, 3 Feb 2018 10:25:27 +0100
Subject: [PATCH 4/6] Microtelecom Perseus HF receiver support
---
CMakeLists.txt | 1 +
cmake/Modules/FindLibPERSEUS.cmake | 24 ++
lib/CMakeLists.txt | 8 +
lib/config.h.in | 1 +
lib/device.cc | 8 +
lib/perseus/CMakeLists.txt | 37 +++
lib/perseus/perseus_source_c.cc | 613 +++++++++++++++++++++++++++++++++++++
lib/perseus/perseus_source_c.h | 135 ++++++++
lib/source_impl.cc | 18 +-
9 files changed, 844 insertions(+), 1 deletion(-)
create mode 100644 cmake/Modules/FindLibPERSEUS.cmake
create mode 100644 lib/perseus/CMakeLists.txt
create mode 100644 lib/perseus/perseus_source_c.cc
create mode 100644 lib/perseus/perseus_source_c.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 296456d..94acd4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -173,6 +173,7 @@ find_package(Volk)
find_package(LibbladeRF)
find_package(SoapySDR NO_MODULE)
find_package(LibFreeSRP)
+find_package(LibPERSEUS)
find_package(Doxygen)
if(NOT GNURADIO_RUNTIME_FOUND)
diff --git a/cmake/Modules/FindLibPERSEUS.cmake b/cmake/Modules/FindLibPERSEUS.cmake
new file mode 100644
index 0000000..5477327
--- /dev/null
+++ b/cmake/Modules/FindLibPERSEUS.cmake
@@ -0,0 +1,24 @@
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(PC_LIBPERSEUS libperseus-sdr)
+
+FIND_PATH(
+ LIBPERSEUS_INCLUDE_DIRS
+ NAMES perseus-sdr.h
+ HINTS $ENV{LIBPERSEUS_DIR}/include
+ ${PC_LIBPERSEUS_INCLUDEDIR}
+ PATHS /usr/local/include
+ /usr/include
+)
+
+FIND_LIBRARY(
+ LIBPERSEUS_LIBRARIES
+ NAMES perseus-sdr
+ HINTS $ENV{LIBPERSEUS_DIR}/lib
+ ${PC_LIBPERSEUS_LIBDIR}
+ PATHS /usr/local/lib
+ /usr/lib
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBPERSEUS DEFAULT_MSG LIBPERSEUS_LIBRARIES LIBPERSEUS_INCLUDE_DIRS)
+MARK_AS_ADVANCED(LIBPERSEUS_LIBRARIES LIBPERSEUS_INCLUDE_DIRS)
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index c05b8d9..f555816 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -249,6 +249,14 @@ GR_INCLUDE_SUBDIRECTORY(freesrp)
endif(ENABLE_FREESRP)
########################################################################
+# Setup PERSEUS component
+########################################################################
+GR_REGISTER_COMPONENT("Microtelecom Perseus Receiver" ENABLE_PERSEUS LIBPERSEUS_FOUND)
+if(ENABLE_PERSEUS)
+GR_INCLUDE_SUBDIRECTORY(perseus)
+endif(ENABLE_PERSEUS)
+
+########################################################################
# Setup configuration file
########################################################################
ADD_DEFINITIONS(-DHAVE_CONFIG_H=1)
diff --git a/lib/config.h.in b/lib/config.h.in
index 42e72f1..dac7e39 100644
--- a/lib/config.h.in
+++ b/lib/config.h.in
@@ -19,6 +19,7 @@
#cmakedefine ENABLE_SOAPY
#cmakedefine ENABLE_REDPITAYA
#cmakedefine ENABLE_FREESRP
+#cmakedefine ENABLE_PERSEUS
//provide NAN define for MSVC older than VC12
#if defined(_MSC_VER) && (_MSC_VER < 1800)
diff --git a/lib/device.cc b/lib/device.cc
index 025a22b..df0d734 100644
--- a/lib/device.cc
+++ b/lib/device.cc
@@ -90,6 +90,10 @@
#include <freesrp_source_c.h>
#endif
+#ifdef ENABLE_PERSEUS
+#include <perseus_source_c.h>
+#endif
+
#include "arg_helpers.h"
using namespace osmosdr;
@@ -194,6 +198,10 @@ devices_t device::find(const device_t &hint)
BOOST_FOREACH( std::string dev, soapy_source_c::get_devices() )
devices.push_back( device_t(dev) );
#endif
+#ifdef ENABLE_PERSEUS
+ BOOST_FOREACH( std::string dev, perseus_source_c::get_devices() )
+ devices.push_back( device_t(dev) );
+#endif
/* software-only sources should be appended at the very end,
* hopefully resulting in hardware sources to be shown first
diff --git a/lib/perseus/CMakeLists.txt b/lib/perseus/CMakeLists.txt
new file mode 100644
index 0000000..f45a10d
--- /dev/null
+++ b/lib/perseus/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright 2017 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+########################################################################
+# This file included, use CMake directory variables
+########################################################################
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${LIBPERSEUS_INCLUDE_DIRS}
+)
+
+set(perseus_srcs
+ ${CMAKE_CURRENT_SOURCE_DIR}/perseus_source_c.cc
+)
+
+########################################################################
+# Append gnuradio-osmosdr library sources
+########################################################################
+list(APPEND gr_osmosdr_srcs ${perseus_srcs})
+list(APPEND gr_osmosdr_libs ${LIBPERSEUS_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES})
diff --git a/lib/perseus/perseus_source_c.cc b/lib/perseus/perseus_source_c.cc
new file mode 100644
index 0000000..bf7c9be
--- /dev/null
+++ b/lib/perseus/perseus_source_c.cc
@@ -0,0 +1,613 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2018 Andrea Montefusco IW0HDV
+ *
+ * GNU Radio 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; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * config.h is generated by configure. It contains the results
+ * of probing for features, options etc. It should be the first
+ * file included in your .cc file.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdexcept>
+#include <iostream>
+#include <algorithm>
+
+#include <boost/assign.hpp>
+#include <boost/format.hpp>
+#include <boost/detail/endian.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <gnuradio/io_signature.h>
+
+#include "perseus_source_c.h"
+#include "arg_helpers.h"
+
+
+
+using namespace boost::assign;
+
+#define PERSEUS_FORMAT_ERROR(ret, msg) \
+ boost::str( boost::format(msg " (%1%)") % ret )
+
+#define PERSEUS_THROW_ON_ERROR(ret, msg) \
+ if ( ret != PERSEUS_NOERROR ) \
+ { \
+ throw std::runtime_error( PERSEUS_FORMAT_ERROR(ret, msg) ); \
+ }
+
+#define PERSEUS_FUNC_STR(func, arg) \
+ boost::str(boost::format(func "(%1%)") % arg) + " has failed"
+
+perseus_source_c_sptr make_perseus_source_c (const std::string & args)
+{
+ return gnuradio::get_initial_sptr(new perseus_source_c (args));
+}
+
+/*
+ * Specify constraints on number of input and output streams.
+ * This info is used to construct the input and output signatures
+ * (2nd & 3rd args to gr::block's constructor). The input and
+ * output signatures are used by the runtime system to
+ * check that a valid number and type of inputs and outputs
+ * are connected to this block. In this case, we accept
+ * only 0 input and 1 output.
+ */
+static const int MIN_IN = 0; // mininum number of input streams
+static const int MAX_IN = 0; // maximum number of input streams
+static const int MIN_OUT = 1; // minimum number of output streams
+static const int MAX_OUT = 1; // maximum number of output streams
+
+/*
+ * The private constructor
+ */
+perseus_source_c::perseus_source_c (const std::string &args)
+ : gr::sync_block ("perseus_source_c",
+ gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)),
+ gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))),
+ _dev(NULL),
+ _sample_rate(0),
+ _center_freq(0),
+ _freq_corr(0),
+ _frun(false),
+ _cnt(0),
+ _att_value(0),
+ _adc_preamp(false),
+ _adc_dither(false),
+ _preselector(false)
+{
+ dict_t dict = params_to_dict(args);
+
+ _dev = NULL;
+
+ // Set debug info dumped to stderr to the maximum verbose level
+ perseus_set_debug(3);
+
+ // Check how many Perseus receivers are connected to the system
+ int num_perseus = perseus_init();
+ std::cerr << "## Microtelecom Perseus ctor: " << num_perseus << " Perseus receivers found." << std::endl;
+
+ if (num_perseus==0) {
+ perseus_exit();
+ PERSEUS_THROW_ON_ERROR(PERSEUS_DEVNOTFOUND, "No Perseus receivers detected");
+ }
+ // Open the first one...
+ if ((_dev = perseus_open(0)) == NULL) {
+ PERSEUS_THROW_ON_ERROR(PERSEUS_DEVNOTFOUND, "Unable to open Perseus device");
+ }
+ // Download the standard firmware to the unit
+ std::cerr << "Downloading firmware..." << std::endl;
+ if (int rc = perseus_firmware_download(_dev,NULL)<0) {
+ PERSEUS_THROW_ON_ERROR (rc, "firmware download error");
+ }
+
+ // Dump some information about the receiver (S/N and HW rev)
+ int flag;
+ perseus_is_preserie(_dev, &flag);
+ if (flag != 0)
+ fprintf(stderr, "The device is a preserie unit");
+ else {
+ eeprom_prodid prodid;
+ if (perseus_get_product_id(_dev,&prodid)<0)
+ fprintf(stderr, "get product id error: %s", perseus_errorstr());
+ else
+ fprintf(stderr, "Receiver S/N: %05d-%02hX%02hX-%02hX%02hX-%02hX%02hX - HW Release:%hd.%hd\n",
+ (uint16_t) prodid.sn,
+ (uint16_t) prodid.signature[5],
+ (uint16_t) prodid.signature[4],
+ (uint16_t) prodid.signature[3],
+ (uint16_t) prodid.signature[2],
+ (uint16_t) prodid.signature[1],
+ (uint16_t) prodid.signature[0],
+ (uint16_t) prodid.hwrel,
+ (uint16_t) prodid.hwver);
+ }
+ // Printing all sampling rates available .....
+ {
+ int buf[BUFSIZ];
+
+ if (perseus_get_sampling_rates (_dev, buf, sizeof(buf)/sizeof(buf[0])) < 0) {
+ fprintf(stderr, "get sampling rates error: %s\n", perseus_errorstr());
+ } else {
+ int i = 0;
+ while (buf[i]) {
+ fprintf(stderr, "#%d: sample rate: %d\n", i, buf[i]);
+ _sample_rates.push_back( std::pair<double, uint32_t>( buf[i], i ) );
+ i++;
+ }
+ /* since they may (and will) give us an unsorted array we have to sort it here
+ * to play nice with the monotonic requirement of meta-range later on */
+ std::sort(_sample_rates.begin(), _sample_rates.end());
+
+ for (size_t i = 0; i < _sample_rates.size(); i++)
+ std::cerr << boost::format("%gM ") % (_sample_rates[i].first / 1e6);
+
+ std::cerr << std::endl;
+ }
+ }
+ // Configure the receiver for 2 MS/s operations
+ fprintf(stderr, "Configuring FPGA...\n");
+ if (int ret = perseus_set_sampling_rate(_dev, 96000) < 0) { // specify the sampling rate value in Samples/second
+ std::cerr << "fpga configuration error: " << perseus_errorstr() << std::endl;
+ PERSEUS_THROW_ON_ERROR(ret, "Perseus fpga configuration error");
+ }
+
+ perseus_set_attenuator_in_db(_dev, _att_value);
+ // Enable ADC Dither, Disable ADC Preamp
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ // set the NCO frequency in the middle of the range allowed
+ set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 );
+ set_sample_rate( get_sample_rates().start() );
+
+ _fifo = new boost::circular_buffer<gr_complex>(5000000);
+ if (!_fifo) {
+ throw std::runtime_error( std::string(__FUNCTION__) + " " +
+ "Failed to allocate a sample FIFO!" );
+ }
+}
+
+/*
+ * Our virtual destructor.
+ */
+perseus_source_c::~perseus_source_c ()
+{
+ if (_dev) {
+ if (_frun) stop();
+ int ret = perseus_close(_dev);
+ if ( ret != PERSEUS_NOERROR ) {
+ std::cerr << PERSEUS_FORMAT_ERROR(ret, "Failed to close Perseus") << std::endl;
+ } else
+ _dev = NULL;
+ }
+ perseus_exit();
+
+ if (_fifo) {
+ delete _fifo;
+ _fifo = NULL;
+ }
+}
+
+
+typedef union {
+ struct {
+ int32_t i;
+ int32_t q;
+ } __attribute__((__packed__)) iq;
+ struct {
+ uint8_t i1;
+ uint8_t i2;
+ uint8_t i3;
+ uint8_t i4;
+ uint8_t q1;
+ uint8_t q2;
+ uint8_t q3;
+ uint8_t q4;
+ } __attribute__((__packed__)) ;
+} iq_sample;
+
+
+int perseus_source_c::perseus_rx_callback(void *buf, int buf_size)
+{
+ size_t i, n_avail, to_copy, num_samples;
+
+ uint8_t *samplebuf = (uint8_t*)buf;
+
+ num_samples = buf_size/6;
+
+ if (buf_size % 6)
+ std::cerr << "FATAL !!!!!!! not on boundary" << std::endl;
+
+ iq_sample s;
+
+ _fifo_lock.lock();
+
+ n_avail = _fifo->capacity() - _fifo->size();
+ to_copy = (n_avail < num_samples ? n_avail : num_samples);
+
+ for (i = 0; i < to_copy; i++ ) {
+
+ s.i1 = s.q1 = 0;
+ s.i2 = *samplebuf++;
+ s.i3 = *samplebuf++;
+ s.i4 = *samplebuf++;
+ s.q2 = *samplebuf++;
+ s.q3 = *samplebuf++;
+ s.q4 = *samplebuf++;
+
+ // convert 24 bit two's complements integers to float in [-1.0 - +1.0] range
+ // Push sample to the fifo
+ _fifo->push_back( gr_complex( (float)(s.iq.i) / (INT_MAX - 256), (float)(s.iq.q) / (INT_MAX - 256) ) );
+
+ }
+ // keep a counter of processed bytes
+ _cnt += buf_size;
+
+ _fifo_lock.unlock();
+
+ /* We have made some new samples available to the consumer in work() */
+ if (to_copy) {
+ //std::cerr << "+" << std::flush;
+ _samp_avail.notify_one();
+ }
+
+ /* Indicate overrun, if necessary */
+ if (to_copy < num_samples)
+ std::cerr << "O" << std::flush;
+
+ return 0; // TODO: return -1 on error/stop
+}
+
+// static method used as callback from the libperseus-sdr library
+int perseus_source_c::_perseus_rx_callback(void *buf, int buf_size, void *extra)
+{
+ perseus_source_c *obj = (perseus_source_c *)extra;
+
+ return obj->perseus_rx_callback((float *)buf, buf_size);
+
+ return 0;
+}
+
+
+bool perseus_source_c::start()
+{
+ int ret;
+
+ if ( ! _dev )
+ return false;
+
+ std::cerr << "***** START COUNTER: " << _cnt
+ << " mod 6 " << (_cnt % 6) << std::endl;
+
+ _frun = true;
+
+ // in order to guarantee samples stream synchronization
+ // re-set the sample rate each time the stream is started
+ set_sample_rate( get_sample_rate() );
+
+ ret = perseus_start_async_input(_dev,
+ 6 * 1024 * 2 /* buffer size */,
+ perseus_source_c::_perseus_rx_callback,
+ (void *)this);
+ if (ret != PERSEUS_NOERROR) {
+ std::cerr << "Failed to start RX streaming ("
+ << ret << ")" << std::endl;
+ return false;
+ } else
+ return true;
+}
+
+bool perseus_source_c::stop()
+{
+ if ( ! _dev )
+ return false;
+
+ _frun = false;
+
+ std::cerr << "***** STOP COUNTER: " << _cnt
+ << " mod 6 " << (_cnt % 6) << std::endl;
+
+ int ret = perseus_stop_async_input(_dev);
+
+ if ( ret != PERSEUS_NOERROR ) {
+ std::cerr << "Failed to stop RX streaming (" << ret << ")" << std::endl;
+ return false;
+ } else
+ return true;
+}
+
+int perseus_source_c::work( int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items )
+{
+ gr_complex *out = (gr_complex *)output_items[0];
+
+ if ( _frun == false ) return WORK_DONE;
+
+ boost::unique_lock<boost::mutex> lock(_fifo_lock);
+
+ /* Wait until we have the requested number of samples */
+ int n_samples_avail = _fifo->size();
+
+ while (n_samples_avail < noutput_items) {
+ _samp_avail.wait(lock);
+ n_samples_avail = _fifo->size();
+ }
+
+ for(int i = 0; i < noutput_items; ++i) {
+ out[i] = _fifo->at(0);
+ _fifo->pop_front();
+ }
+
+ return noutput_items;
+}
+
+std::vector<std::string> perseus_source_c::get_devices()
+{
+ std::vector<std::string> devices;
+ std::string label;
+
+ std::string args = "perseus=0,label='Perseus'";
+ devices.push_back( args );
+
+ return devices;
+}
+
+size_t perseus_source_c::get_num_channels()
+{
+ return 1;
+}
+
+osmosdr::meta_range_t perseus_source_c::get_sample_rates()
+{
+ osmosdr::meta_range_t range;
+
+ for (size_t i = 0; i < _sample_rates.size(); i++) {
+ range += osmosdr::range_t( _sample_rates[i].first );
+ std::cerr << "SR: " << i << " : ("
+ << _sample_rates[i].first << ")" << std::endl;
+ }
+ return range;
+}
+
+double perseus_source_c::set_sample_rate( double rate )
+{
+ int ret;
+ if ((ret = perseus_set_sampling_rate(_dev, rate)) < 0) {
+ PERSEUS_THROW_ON_ERROR(ret, "Unable to set sample rate.");
+ } else
+ _sample_rate = rate;
+
+ return get_sample_rate();
+}
+
+double perseus_source_c::get_sample_rate()
+{
+ return _sample_rate;
+}
+
+osmosdr::freq_range_t perseus_source_c::get_freq_range( size_t chan )
+{
+ osmosdr::freq_range_t range;
+
+ range += osmosdr::range_t( PERSEUS_DDC_FREQ_MIN, PERSEUS_DDC_FREQ_MAX );
+
+ return range;
+}
+
+double perseus_source_c::set_center_freq( double freq, size_t chan )
+{
+ int ret;
+
+ if (_dev) {
+ ret =
+ perseus_set_ddc_center_freq(_dev,
+ (uint64_t)(freq * (1.0 + (_freq_corr * 10e-6))),
+ _preselector == true ? 1:0);
+ if ( ret == PERSEUS_NOERROR ) {
+ _center_freq = freq;
+ } else {
+ PERSEUS_THROW_ON_ERROR( ret, PERSEUS_FUNC_STR( "perseus_set_ddc_center_freq", freq ) )
+ }
+ }
+
+ return get_center_freq( chan );
+}
+
+double perseus_source_c::get_center_freq( size_t chan )
+{
+ return _center_freq;
+}
+
+double perseus_source_c::set_freq_corr( double ppm, size_t chan )
+{
+ return _freq_corr = ppm;
+}
+
+double perseus_source_c::get_freq_corr( size_t chan )
+{
+ return _freq_corr;
+}
+
+std::vector<std::string> perseus_source_c::get_gain_names( size_t chan )
+{
+ std::vector< std::string > names;
+
+ names += "Attenuator";
+ names += "ADC preamp";
+ names += "ADC dither";
+
+ return names;
+}
+
+//
+// FIXME
+//
+osmosdr::gain_range_t perseus_source_c::get_gain_range( size_t chan )
+{
+ return get_gain_range( "Attenuator", chan );
+}
+
+osmosdr::gain_range_t perseus_source_c::get_gain_range( const std::string & name, size_t chan )
+{
+ if ( "Attenuator" == name ) {
+ return osmosdr::gain_range_t( -30, 0, 10 );
+ }
+ if ( "ADC preamp" == name ) {
+ return osmosdr::gain_range_t( 0, 6, 6 );
+ }
+ if ( "ADC dither" == name ) {
+ return osmosdr::gain_range_t( 0, 1, 1 );
+ }
+
+ return osmosdr::gain_range_t();
+}
+
+
+double perseus_source_c::set_attenuator( double gain, size_t chan )
+{
+ int ret;
+
+ gain = - gain;
+ if (_dev && _att_value != gain) {
+ ret = perseus_set_attenuator_in_db (_dev, gain);
+
+ if ( PERSEUS_NOERROR == ret ) {
+ _att_value = gain;
+ } else {
+ std::cerr << "ERROR: perseus_set_attenuator_in_db: " << gain << std::endl;
+ }
+ }
+
+ return _att_value;
+}
+
+double perseus_source_c::set_adc_preamp( double gain, size_t chan )
+{
+ std::cerr << "set_adc_preamp: " << gain << std::endl;
+
+ if (_dev) {
+ _adc_preamp = (gain != 0. ? true : false);
+ int ret =
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ if ( PERSEUS_NOERROR != ret ) {
+ std::cerr << "ERROR: perseus_set_adc" << ret << std::endl;
+ }
+ }
+ return gain;
+}
+
+double perseus_source_c::set_adc_dither( double gain, size_t chan )
+{
+ std::cerr << "set_adc_dither: " << gain << std::endl;
+
+ if (_dev) {
+ _adc_dither = (gain != 0. ? true : false);
+ int ret =
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ if ( PERSEUS_NOERROR != ret ) {
+ std::cerr << "ERROR: perseus_set_adc" << ret << std::endl;
+ }
+ }
+ return gain;
+}
+
+double perseus_source_c::get_attenuator( size_t chan )
+{
+ return _att_value;
+}
+
+double perseus_source_c::get_adc_preamp(size_t chan )
+{
+ double v = _adc_preamp == true ? 6. : 0.;
+ std::cerr << "get_adc_preamp: " << _adc_preamp << " value" << v << std::endl;
+ return v;
+}
+
+double perseus_source_c::get_adc_dither(size_t chan )
+{
+ double v = _adc_dither == true ? 1. : 0.;
+ std::cerr << "get_adc_dither: " << _adc_dither << " value" << v << std::endl;
+ return v;
+}
+
+
+double perseus_source_c::set_gain( double gain, const std::string & name, size_t chan)
+{
+ if ( "Attenuator" == name ) {
+ return set_attenuator( gain, chan );
+ }
+ if ( "ADC preamp" == name ) {
+ return set_adc_preamp( gain, chan );
+ }
+ if ( "ADC dither" == name ) {
+ return set_adc_dither( gain, chan );
+ }
+ return gain;
+}
+
+
+double perseus_source_c::get_gain( const std::string & name, size_t chan )
+{
+ if ( "Attenuator" == name ) {
+ return get_attenuator( chan );
+ }
+ if ( "ADC preamp" == name ) {
+ return get_adc_preamp( chan );
+ }
+ if ( "ADC dither" == name ) {
+ return get_adc_dither( chan );
+ }
+ return 0.0;
+}
+
+
+
+std::vector< std::string > perseus_source_c::get_antennas( size_t chan )
+{
+ std::vector< std::string > antennas;
+
+ antennas += "RX";
+ antennas += "RX+PRESELECTOR";
+
+ return antennas;
+}
+
+std::string perseus_source_c::set_antenna( const std::string & antenna, size_t chan )
+{
+ if ( antenna == "RX" ) {
+ _preselector = false;
+ set_center_freq( get_center_freq() );
+ return "RX";
+ }
+ if ( antenna == "RX+PRESELECTOR" ) {
+ _preselector = true;
+ set_center_freq( get_center_freq() );
+ return "RX+PRESELECTOR";
+ }
+ return get_antenna( chan );
+}
+
+std::string perseus_source_c::get_antenna( size_t chan )
+{
+ std::cerr << "perseus_source_c::get_antenna: " << chan << std::endl;
+ return "RX";
+}
diff --git a/lib/perseus/perseus_source_c.h b/lib/perseus/perseus_source_c.h
new file mode 100644
index 0000000..55d3f89
--- /dev/null
+++ b/lib/perseus/perseus_source_c.h
@@ -0,0 +1,135 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Dimitri Stolnikov <horiz0n(a)gmx.net>
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio 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; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef INCLUDED_PERSEUS_SOURCE_C_H
+#define INCLUDED_PERSEUS_SOURCE_C_H
+
+#include <boost/circular_buffer.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+
+#include <gnuradio/sync_block.h>
+
+#include "source_iface.h"
+#include <perseus-sdr.h>
+
+class perseus_source_c;
+
+typedef boost::shared_ptr<perseus_source_c> perseus_source_c_sptr;
+
+/*!
+ * \brief Return a shared_ptr to a new instance of perseus_source_c.
+ *
+ * To avoid accidental use of raw pointers, perseus_source_c's
+ * constructor is private. make_perseus_source_c is the public
+ * interface for creating new instances.
+ */
+perseus_source_c_sptr make_perseus_source_c (const std::string & args = "");
+
+/*!
+ * \brief Provides a stream of complex samples.
+ * \ingroup block
+ */
+class perseus_source_c :
+ public gr::sync_block,
+ public source_iface
+{
+private:
+ // The friend declaration allows make_perseus_source_c to
+ // access the private constructor.
+
+ friend perseus_source_c_sptr make_perseus_source_c (const std::string & args);
+
+ perseus_source_c (const std::string & args);
+
+public:
+ ~perseus_source_c ();
+
+ bool start();
+ bool stop();
+
+ int work( int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items );
+
+ static std::vector< std::string > get_devices();
+
+ size_t get_num_channels( void );
+
+ osmosdr::meta_range_t get_sample_rates( void );
+ double set_sample_rate( double rate );
+ double get_sample_rate( void );
+
+ osmosdr::freq_range_t get_freq_range( size_t chan = 0 );
+ double set_center_freq( double freq, size_t chan = 0 );
+ double get_center_freq( size_t chan = 0 );
+ double set_freq_corr( double ppm, size_t chan = 0 );
+ double get_freq_corr( size_t chan = 0 );
+
+ std::vector<std::string> get_gain_names( size_t chan = 0 );
+ osmosdr::gain_range_t get_gain_range( size_t chan = 0 );
+ osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 );
+
+ double set_gain( double gain, size_t chan = 0 ) {return gain; }
+ double get_gain( size_t chan = 0 ) {return _att_value; }
+
+ double set_attenuator( double gain, size_t chan = 0 );
+ double get_attenuator( size_t chan = 0 );
+
+ double set_adc_preamp( double gain, size_t chan = 0 );
+ double get_adc_preamp( size_t chan = 0 );
+
+ double set_adc_dither( double gain, size_t chan = 0 );
+ double get_adc_dither( size_t chan = 0 );
+
+ double set_gain( double gain, const std::string & name, size_t chan = 0 );
+ double get_gain( const std::string & name, size_t chan = 0 );
+
+ std::vector< std::string > get_antennas( size_t chan = 0 );
+ std::string set_antenna( const std::string & antenna, size_t chan = 0 );
+ std::string get_antenna( size_t chan = 0 );
+
+
+private:
+ static int _perseus_rx_callback(void *buf, int buf_size, void *extra);
+
+ int perseus_rx_callback(void *samples, int sample_count);
+
+ perseus_descr *_dev;
+
+ boost::circular_buffer<gr_complex> *_fifo;
+ boost::mutex _fifo_lock;
+ boost::condition_variable _samp_avail;
+
+ std::vector< std::pair<double, uint32_t> > _sample_rates;
+ double _sample_rate;
+ double _center_freq;
+ double _freq_corr;
+
+ bool _frun;
+ int _cnt;
+ double _att_value;
+ bool _adc_preamp;
+ bool _adc_dither;
+ bool _preselector;
+};
+
+#endif /* INCLUDED_PERSEUS_SOURCE_C_H */
diff --git a/lib/source_impl.cc b/lib/source_impl.cc
index a28f314..ead4ef7 100644
--- a/lib/source_impl.cc
+++ b/lib/source_impl.cc
@@ -92,6 +92,9 @@
#include <freesrp_source_c.h>
#endif
+#ifdef ENABLE_PERSEUS
+#include <perseus_source_c.h>
+#endif
#include "arg_helpers.h"
#include "source_impl.h"
@@ -171,6 +174,9 @@ source_impl::source_impl( const std::string &args )
#ifdef ENABLE_FREESRP
dev_types.push_back("freesrp");
#endif
+#ifdef ENABLE_PERSEUS
+ dev_types.push_back("perseus");
+#endif
std::cerr << "gr-osmosdr "
<< GR_OSMOSDR_VERSION << " (" << GR_OSMOSDR_LIBVER << ") "
<< "gnuradio " << gr::version() << std::endl;
@@ -252,7 +258,10 @@ source_impl::source_impl( const std::string &args )
BOOST_FOREACH( std::string dev, freesrp_source_c::get_devices() )
dev_list.push_back( dev );
#endif
-
+#ifdef ENABLE_PERSEUS
+ BOOST_FOREACH( std::string dev, perseus_source_c::get_devices() )
+ dev_list.push_back( dev );
+#endif
// std::cerr << std::endl;
// BOOST_FOREACH( std::string dev, dev_list )
// std::cerr << "'" << dev << "'" << std::endl;
@@ -383,6 +392,13 @@ source_impl::source_impl( const std::string &args )
}
#endif
+#ifdef ENABLE_PERSEUS
+ if ( dict.count("perseus") ) {
+ perseus_source_c_sptr src = make_perseus_source_c( arg );
+ block = src; iface = src.get();
+ }
+#endif
+
if ( iface != NULL && long(block.get()) != 0 ) {
_devs.push_back( iface );
--
1.9.1
>From 9be9bfc531d793f0d3d728c361f0b7f520d5c991 Mon Sep 17 00:00:00 2001
From: Andrea Montefusco IW0HDV <andrew(a)montefusco.com>
Date: Tue, 27 Mar 2018 20:35:30 +0200
Subject: [PATCH 5/6] Avoid to throw exception when the new frequency is out of
range; it happens when we are coming back to Perseus from wider range
receivers
---
lib/perseus/perseus_source_c.cc | 76 ++++++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 36 deletions(-)
diff --git a/lib/perseus/perseus_source_c.cc b/lib/perseus/perseus_source_c.cc
index 89674b1..faab51d 100644
--- a/lib/perseus/perseus_source_c.cc
+++ b/lib/perseus/perseus_source_c.cc
@@ -103,15 +103,15 @@ perseus_source_c::perseus_source_c (const std::string &args)
// Set debug info dumped to stderr to the maximum verbose level
perseus_set_debug(3);
-
+
//fprintf (stderr, "Revision: %s\n", git_revision);
//fprintf (stderr, "SAMPLE RATE: %d\n", sr);
//fprintf (stderr, "NBUF: %d BUF SIZE: %d TOTAL BUFFER LENGTH: %d\n", nb, bs, nb*bs);
-
+
// Check how many Perseus receivers are connected to the system
int num_perseus = perseus_init();
std::cerr << "## Microtelecom Perseus ctor: " << num_perseus << " Perseus receivers found." << std::endl;
-
+
if (num_perseus==0) {
perseus_exit();
PERSEUS_THROW_ON_ERROR(PERSEUS_DEVNOTFOUND, "No Perseus receivers detected");
@@ -125,19 +125,19 @@ perseus_source_c::perseus_source_c (const std::string &args)
if (int rc = perseus_firmware_download(_dev,NULL)<0) {
PERSEUS_THROW_ON_ERROR (rc, "firmware download error");
}
-
+
// Dump some information about the receiver (S/N and HW rev)
int flag;
perseus_is_preserie(_dev, &flag);
- if (flag != 0)
+ if (flag != 0)
fprintf(stderr, "The device is a preserie unit");
else {
eeprom_prodid prodid;
- if (perseus_get_product_id(_dev,&prodid)<0)
+ if (perseus_get_product_id(_dev,&prodid)<0)
fprintf(stderr, "get product id error: %s", perseus_errorstr());
else
fprintf(stderr, "Receiver S/N: %05d-%02hX%02hX-%02hX%02hX-%02hX%02hX - HW Release:%hd.%hd\n",
- (uint16_t) prodid.sn,
+ (uint16_t) prodid.sn,
(uint16_t) prodid.signature[5],
(uint16_t) prodid.signature[4],
(uint16_t) prodid.signature[3],
@@ -146,18 +146,18 @@ perseus_source_c::perseus_source_c (const std::string &args)
(uint16_t) prodid.signature[0],
(uint16_t) prodid.hwrel,
(uint16_t) prodid.hwver);
- }
+ }
// Printing all sampling rates available .....
{
int buf[BUFSIZ];
-
+
if (perseus_get_sampling_rates (_dev, buf, sizeof(buf)/sizeof(buf[0])) < 0) {
fprintf(stderr, "get sampling rates error: %s\n", perseus_errorstr());
} else {
int i = 0;
while (buf[i]) {
fprintf(stderr, "#%d: sample rate: %d\n", i, buf[i]);
-
+
_sample_rates.push_back( std::pair<double, uint32_t>( buf[i], i ) );
i++;
}
@@ -177,14 +177,14 @@ perseus_source_c::perseus_source_c (const std::string &args)
std::cerr << "fpga configuration error: " << perseus_errorstr() << std::endl;
PERSEUS_THROW_ON_ERROR(ret, "Perseus fpga configuration error");
}
-
+
perseus_set_attenuator_in_db(_dev, _att_value);
// Enable ADC Dither, Disable ADC Preamp
perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
// set the NCO frequency in the middle of the range allowed
set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 );
set_sample_rate( get_sample_rates().start() );
-
+
_fifo = new boost::circular_buffer<gr_complex>(5000000);
if (!_fifo) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
@@ -237,10 +237,10 @@ int perseus_source_c::perseus_rx_callback(void *buf, int buf_size)
size_t i, n_avail, to_copy, num_samples;
uint8_t *samplebuf = (uint8_t*)buf;
-
+
num_samples = buf_size/6;
- if (buf_size % 6)
+ if (buf_size % 6)
std::cerr << "FATAL !!!!!!! not on boundary" << std::endl;
iq_sample s;
@@ -251,7 +251,7 @@ int perseus_source_c::perseus_rx_callback(void *buf, int buf_size)
to_copy = (n_avail < num_samples ? n_avail : num_samples);
for (i = 0; i < to_copy; i++ ) {
-
+
s.i1 = s.q1 = 0;
s.i2 = *samplebuf++;
s.i3 = *samplebuf++;
@@ -259,16 +259,16 @@ int perseus_source_c::perseus_rx_callback(void *buf, int buf_size)
s.q2 = *samplebuf++;
s.q3 = *samplebuf++;
s.q4 = *samplebuf++;
-
+
// convert 24 bit two's complements integers to float in [-1.0 - +1.0] range
-
+
/* Push sample to the fifo */
_fifo->push_back( gr_complex( (float)(s.iq.i) / (INT_MAX - 256), (float)(s.iq.q) / (INT_MAX - 256) ) );
}
// keep a counter of processed bytes
_cnt += buf_size;
-
+
_fifo_lock.unlock();
/* We have made some new samples available to the consumer in work() */
@@ -290,7 +290,7 @@ int perseus_source_c::_perseus_rx_callback(void *buf, int buf_size, void *extra)
perseus_source_c *obj = (perseus_source_c *)extra;
return obj->perseus_rx_callback((float *)buf, buf_size);
-
+
return 0;
}
@@ -301,8 +301,8 @@ bool perseus_source_c::start()
if ( ! _dev )
return false;
-
- std::cerr << "***** START COUNTER: " << _cnt
+
+ std::cerr << "***** START COUNTER: " << _cnt
<< " mod 6 " << (_cnt % 6) << std::endl;
_frun = true;
@@ -311,15 +311,15 @@ bool perseus_source_c::start()
// re-set the sample rate each time the stream is started
set_sample_rate( get_sample_rate() );
- ret = perseus_start_async_input(_dev,
- 6 * 1024 * 2 /* buffer size */,
+ ret = perseus_start_async_input(_dev,
+ 6 * 1024 * 2 /* buffer size */,
perseus_source_c::_perseus_rx_callback,
(void *)this);
if (ret != PERSEUS_NOERROR) {
- std::cerr << "Failed to start RX streaming ("
+ std::cerr << "Failed to start RX streaming ("
<< ret << ")" << std::endl;
- return false;
- } else
+ return false;
+ } else
return true;
}
@@ -330,15 +330,15 @@ bool perseus_source_c::stop()
_frun = false;
- std::cerr << "***** STOP COUNTER: " << _cnt
+ std::cerr << "***** STOP COUNTER: " << _cnt
<< " mod 6 " << (_cnt % 6) << std::endl;
int ret = perseus_stop_async_input(_dev);
if ( ret != PERSEUS_NOERROR ) {
std::cerr << "Failed to stop RX streaming (" << ret << ")" << std::endl;
- return false;
- } else
+ return false;
+ } else
return true;
}
@@ -375,7 +375,7 @@ std::vector<std::string> perseus_source_c::get_devices()
std::string args = "perseus=0,label='Perseus'";
devices.push_back( args );
-
+
return devices;
}
@@ -390,7 +390,7 @@ osmosdr::meta_range_t perseus_source_c::get_sample_rates()
for (size_t i = 0; i < _sample_rates.size(); i++) {
range += osmosdr::range_t( _sample_rates[i].first );
- std::cerr << "SR: " << i << " : ("
+ std::cerr << "SR: " << i << " : ("
<< _sample_rates[i].first << ")" << std::endl;
}
return range;
@@ -400,10 +400,10 @@ double perseus_source_c::set_sample_rate( double rate )
{
int ret;
if ((ret = perseus_set_sampling_rate(_dev, rate)) < 0) {
- PERSEUS_THROW_ON_ERROR(ret, "Unable to set sample rate.");
- } else
+ PERSEUS_THROW_ON_ERROR(ret, "Unable to set sample rate.");
+ } else
_sample_rate = rate;
-
+
return get_sample_rate();
}
@@ -426,9 +426,13 @@ double perseus_source_c::set_center_freq( double freq, size_t chan )
int ret;
if (_dev) {
- ret =
+ // avoid to crash when the frequency is out of range
+ if (freq > PERSEUS_DDC_FREQ_MAX) freq = PERSEUS_DDC_FREQ_MAX;
+ if (freq < PERSEUS_DDC_FREQ_MIN) freq = PERSEUS_DDC_FREQ_MIN;
+
+ ret =
perseus_set_ddc_center_freq(_dev,
- (uint64_t)(freq * (1.0 + (_freq_corr * 10e-6))),
+ (uint64_t)(freq * (1.0 + (_freq_corr * 10e-6))),
_preselector == true ? 1:0);
if ( ret == PERSEUS_NOERROR ) {
_center_freq = freq;
--
1.9.1
>From 38f121f6d823d7971262e0768ab2f8be9ec35e43 Mon Sep 17 00:00:00 2001
From: Andrea Montefusco IW0HDV <andrew(a)montefusco.com>
Date: Tue, 21 Aug 2018 13:49:17 +0200
Subject: [PATCH 6/6] perseus: gr-osmosdr Microtelecom Perseus HF receiver
support
---
AUTHORS | 1 +
MANIFEST.md | 1 +
README | 2 ++
grc/gen_osmosdr_blocks.py | 6 +++++
lib/perseus/perseus_source_c.cc | 57 ++++++++++++++++++++++++++---------------
5 files changed, 46 insertions(+), 21 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index 2fd882c..fd51a22 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,3 +7,4 @@ SDRplay Ltd.
Pavel Demin
Marcus Müller
Lukas Lao Beyer
+Andrea Montefusco IW0HDV <andrew(a)montefusco.com>
diff --git a/MANIFEST.md b/MANIFEST.md
index 9e19f5f..ad33c82 100644
--- a/MANIFEST.md
+++ b/MANIFEST.md
@@ -10,6 +10,7 @@ tags:
- sdrplay
- uhd
- osmocom
+ - perseus
author:
- Dimitri Stolnikov <horiz0n(a)gmx.net>
copyright_owner:
diff --git a/README b/README
index 67fa475..9ff3d5c 100644
--- a/README
+++ b/README
@@ -18,6 +18,8 @@ as well supports:
* Fairwaves UmTRX through Fairwaves' fork of UHD
* Red Pitaya SDR transceiver (http://bazaar.redpitaya.com)
* FreeSRP through libfreesrp
+ * Microtelecom Perseus HF receiver through libperseus-sdr
+ available in https://github.com/Microtelecom/libperseus-sdr/
By using the OsmoSDR block you can take advantage of a common software api in
your application(s) independent of the underlying radio hardware.
diff --git a/grc/gen_osmosdr_blocks.py b/grc/gen_osmosdr_blocks.py
index d1f2b1a..b7e33ef 100644
--- a/grc/gen_osmosdr_blocks.py
+++ b/grc/gen_osmosdr_blocks.py
@@ -219,6 +219,8 @@ While primarily being developed for the OsmoSDR hardware, this block as well sup
* gnuradio .cfile input through libgnuradio-blocks
* RFSPACE SDR-IQ, SDR-IP, NetSDR (incl. X2 option)
* AirSpy Wideband Receiver through libairspy
+ * Microtelecom Perseus HF Receiver through libperseus-sdr
+ available in https://github.com/Microtelecom/libperseus-sdr/
#end if
#if $sourk == 'sink':
* gnuradio .cfile output through libgnuradio-blocks
@@ -260,6 +262,7 @@ Lines ending with ... mean it's possible to bind devices together by specifying
cloudiq=127.0.0.1[:50000]
sdr-iq=/dev/ttyUSB0
airspy=0[,bias=0|1][,linearity][,sensitivity]
+ perseus=0[,attenuator=0|-10|-20|-30][,wideband[0|1]][,adcpreamp=0|1][,adcdither=0|1]
#end if
#if $sourk == 'sink':
file='/path/to/your file',rate=1e6[,freq=100e6][,append=true][,throttle=true] ...
@@ -474,6 +477,9 @@ if __name__ == '__main__':
elif tail.startswith('osmosdr'):
title = 'osmocom'
prefix = 'osmosdr'
+ elif tail.startswith('perseus'):
+ title = 'Perseus'
+ prefix = 'perseus'
else: raise Exception, 'file %s has wrong syntax!'%tail
if tail.endswith ('source.xml'):
diff --git a/lib/perseus/perseus_source_c.cc b/lib/perseus/perseus_source_c.cc
index 3a388d5..4a8f12d 100644
--- a/lib/perseus/perseus_source_c.cc
+++ b/lib/perseus/perseus_source_c.cc
@@ -175,18 +175,36 @@ perseus_source_c::perseus_source_c (const std::string &args)
PERSEUS_THROW_ON_ERROR(ret, "Perseus fpga configuration error");
}
- perseus_set_attenuator_in_db(_dev, _att_value);
- // Enable ADC Dither, Disable ADC Preamp
- perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
- // set the NCO frequency in the middle of the range allowed
- set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 );
- set_sample_rate( get_sample_rates().start() );
-
_fifo = new boost::circular_buffer<gr_complex>(5000000);
if (!_fifo) {
throw std::runtime_error( std::string(__FUNCTION__) + " " +
"Failed to allocate a sample FIFO!" );
}
+
+ int nav = -1;
+ //perseus=0[,attenuator=0|-10|-20|-30][,wideband[0|1]][,adcpreamp=0|1][,adcdither=0|1]
+ if ( dict.count( "attenuator" ) )
+ nav = -(boost::lexical_cast< int >( dict["attenuator"] ));
+ if ( dict.count( "preselector" ) )
+ _preselector = ( boost::lexical_cast< int > ( dict["preselector"] ) == 1 );
+ if ( dict.count( "adcpreamp" ) )
+ _adc_preamp = boost::lexical_cast< int >( dict["adcpreamp"] );
+ if ( dict.count( "adcdither" ) )
+ _adc_dither = boost::lexical_cast< int >( dict["adcdither"] );
+
+
+ // attenuator
+ if (nav != -1) {
+ std::cerr << "perseus_set_attenuator_in_db: new value: " << nav << " old value: " << _att_value << std::endl;
+ perseus_set_attenuator_in_db(_dev, nav);
+ _att_value = nav;
+ }
+ // Enable ADC Dither, Disable ADC Preamp
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ // set the NCO frequency in the middle of the range allowed
+ // and, implicitly, the preselector status
+ set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 );
+ set_sample_rate( get_sample_rates().start() );
}
/*
@@ -465,12 +483,9 @@ std::vector<std::string> perseus_source_c::get_gain_names( size_t chan )
return names;
}
-//
-// FIXME
-//
osmosdr::gain_range_t perseus_source_c::get_gain_range( size_t chan )
{
- return get_gain_range( "Attenuator", chan );
+ return osmosdr::gain_range_t( -30, +7, 1 );
}
osmosdr::gain_range_t perseus_source_c::get_gain_range( const std::string & name, size_t chan )
@@ -491,16 +506,12 @@ osmosdr::gain_range_t perseus_source_c::get_gain_range( const std::string & name
double perseus_source_c::set_attenuator( double gain, size_t chan )
{
- int ret;
-
gain = - gain;
if (_dev && _att_value != gain) {
- ret = perseus_set_attenuator_in_db (_dev, gain);
-
- if ( PERSEUS_NOERROR == ret ) {
+ if ( PERSEUS_NOERROR == perseus_set_attenuator_in_db (_dev, gain) ) {
_att_value = gain;
} else {
- std::cerr << "ERROR: perseus_set_attenuator_in_db: " << gain << std::endl;
+ std::cerr << "ERROR: perseus_set_attenuator_in_db: new value was: " << gain << std::endl;
}
}
@@ -600,21 +611,25 @@ std::vector< std::string > perseus_source_c::get_antennas( size_t chan )
std::string perseus_source_c::set_antenna( const std::string & antenna, size_t chan )
{
+ std::cerr << "perseus_source_c::set_antenna: preselector: " << _preselector << "ch: " << chan << std::endl;
+
if ( antenna == "RX" ) {
_preselector = false;
set_center_freq( get_center_freq() );
- return "RX";
+ return get_antenna(chan);
}
if ( antenna == "RX+PRESELECTOR" ) {
_preselector = true;
set_center_freq( get_center_freq() );
- return "RX+PRESELECTOR";
+ return get_antenna(chan);
}
- return get_antenna( chan );
+ return get_antenna( chan );
}
std::string perseus_source_c::get_antenna( size_t chan )
{
std::cerr << "perseus_source_c::get_antenna: " << chan << std::endl;
- return "RX";
+
+ if (_preselector == false ) return "RX";
+ else return "RX+PRESELECTOR";
}
--
1.9.1
1
0
If there is a better mailing list for the following question, I will gladly take
it there.
I want to use as much of the gnu radio project as
practical but the graphical way to string various modules
together isn't terribly useful for computer users who happen to
be blind.
Unix and to a lesser degree, DOS handled input and output
logic elegantly with <, >, | and even tee when one sends output
to multiple files and unix just turned 50 this Summer so it's
doing something right.
Is there any kind of text-based way to string those python GNU
modules together to cause them to work as they do when
connected using GRC?
This could very well be a dumb question as I have only
scratched at python a few years ago and what I am talking
about may be similar to a Makefile which is what you use to refer
to a bunch of C modules that might be in a program.
Anyway, I sure hope there is something else out there
that accomplishes the same job.
I have played with the Realtek, RTL2838UHIDIR and it does
surprisingly well on analog signals so it's time to string some
of those modules together and try some digital decoding.
Thanks for any and all constructive suggestions.
Martin McCormick WB5AGZ
2
1
trying to figure out what patches to merge for sdrplay2 suppoort. So
far i've received the following sources:
Frank's patch by email on 06/30/18
https://github.com/willcode/gr-osmosdr/tree/sdrplay2
<https://github.com/willcode/gr-osmosdr/tree/sdrplay2>https://github.com/SDRplay/gr-osmosdr/tree/sdrplay2
Could you please comment on whats the most recent and correct state to
apply? Thanks a lot!
Best regards,
Dimitri
3
2
[PATCH] gr-osmosdr Microtelecom Perseus HF receiver support (II)
by andrea.montefusco@gmail.com 16 Aug '18
by andrea.montefusco@gmail.com 16 Aug '18
16 Aug '18
Second attempt: I removed all the changes not related to Perseus.
@Sylvain: thanks for take time to review.
---
CMakeLists.txt | 1 +
cmake/Modules/FindLibPERSEUS.cmake | 24 ++
lib/CMakeLists.txt | 8 +
lib/config.h.in | 1 +
lib/device.cc | 8 +
lib/perseus/CMakeLists.txt | 37 +++
lib/perseus/perseus_source_c.cc | 613 +++++++++++++++++++++++++++++++++++++
lib/perseus/perseus_source_c.h | 135 ++++++++
lib/source_impl.cc | 18 +-
9 files changed, 844 insertions(+), 1 deletion(-)
create mode 100644 cmake/Modules/FindLibPERSEUS.cmake
create mode 100644 lib/perseus/CMakeLists.txt
create mode 100644 lib/perseus/perseus_source_c.cc
create mode 100644 lib/perseus/perseus_source_c.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 296456d..94acd4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -173,6 +173,7 @@ find_package(Volk)
find_package(LibbladeRF)
find_package(SoapySDR NO_MODULE)
find_package(LibFreeSRP)
+find_package(LibPERSEUS)
find_package(Doxygen)
if(NOT GNURADIO_RUNTIME_FOUND)
diff --git a/cmake/Modules/FindLibPERSEUS.cmake b/cmake/Modules/FindLibPERSEUS.cmake
new file mode 100644
index 0000000..5477327
--- /dev/null
+++ b/cmake/Modules/FindLibPERSEUS.cmake
@@ -0,0 +1,24 @@
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(PC_LIBPERSEUS libperseus-sdr)
+
+FIND_PATH(
+ LIBPERSEUS_INCLUDE_DIRS
+ NAMES perseus-sdr.h
+ HINTS $ENV{LIBPERSEUS_DIR}/include
+ ${PC_LIBPERSEUS_INCLUDEDIR}
+ PATHS /usr/local/include
+ /usr/include
+)
+
+FIND_LIBRARY(
+ LIBPERSEUS_LIBRARIES
+ NAMES perseus-sdr
+ HINTS $ENV{LIBPERSEUS_DIR}/lib
+ ${PC_LIBPERSEUS_LIBDIR}
+ PATHS /usr/local/lib
+ /usr/lib
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBPERSEUS DEFAULT_MSG LIBPERSEUS_LIBRARIES LIBPERSEUS_INCLUDE_DIRS)
+MARK_AS_ADVANCED(LIBPERSEUS_LIBRARIES LIBPERSEUS_INCLUDE_DIRS)
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index c05b8d9..f555816 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -249,6 +249,14 @@ GR_INCLUDE_SUBDIRECTORY(freesrp)
endif(ENABLE_FREESRP)
########################################################################
+# Setup PERSEUS component
+########################################################################
+GR_REGISTER_COMPONENT("Microtelecom Perseus Receiver" ENABLE_PERSEUS LIBPERSEUS_FOUND)
+if(ENABLE_PERSEUS)
+GR_INCLUDE_SUBDIRECTORY(perseus)
+endif(ENABLE_PERSEUS)
+
+########################################################################
# Setup configuration file
########################################################################
ADD_DEFINITIONS(-DHAVE_CONFIG_H=1)
diff --git a/lib/config.h.in b/lib/config.h.in
index 42e72f1..dac7e39 100644
--- a/lib/config.h.in
+++ b/lib/config.h.in
@@ -19,6 +19,7 @@
#cmakedefine ENABLE_SOAPY
#cmakedefine ENABLE_REDPITAYA
#cmakedefine ENABLE_FREESRP
+#cmakedefine ENABLE_PERSEUS
//provide NAN define for MSVC older than VC12
#if defined(_MSC_VER) && (_MSC_VER < 1800)
diff --git a/lib/device.cc b/lib/device.cc
index 025a22b..df0d734 100644
--- a/lib/device.cc
+++ b/lib/device.cc
@@ -90,6 +90,10 @@
#include <freesrp_source_c.h>
#endif
+#ifdef ENABLE_PERSEUS
+#include <perseus_source_c.h>
+#endif
+
#include "arg_helpers.h"
using namespace osmosdr;
@@ -194,6 +198,10 @@ devices_t device::find(const device_t &hint)
BOOST_FOREACH( std::string dev, soapy_source_c::get_devices() )
devices.push_back( device_t(dev) );
#endif
+#ifdef ENABLE_PERSEUS
+ BOOST_FOREACH( std::string dev, perseus_source_c::get_devices() )
+ devices.push_back( device_t(dev) );
+#endif
/* software-only sources should be appended at the very end,
* hopefully resulting in hardware sources to be shown first
diff --git a/lib/perseus/CMakeLists.txt b/lib/perseus/CMakeLists.txt
new file mode 100644
index 0000000..f45a10d
--- /dev/null
+++ b/lib/perseus/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright 2017 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+########################################################################
+# This file included, use CMake directory variables
+########################################################################
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${LIBPERSEUS_INCLUDE_DIRS}
+)
+
+set(perseus_srcs
+ ${CMAKE_CURRENT_SOURCE_DIR}/perseus_source_c.cc
+)
+
+########################################################################
+# Append gnuradio-osmosdr library sources
+########################################################################
+list(APPEND gr_osmosdr_srcs ${perseus_srcs})
+list(APPEND gr_osmosdr_libs ${LIBPERSEUS_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES})
diff --git a/lib/perseus/perseus_source_c.cc b/lib/perseus/perseus_source_c.cc
new file mode 100644
index 0000000..bf7c9be
--- /dev/null
+++ b/lib/perseus/perseus_source_c.cc
@@ -0,0 +1,613 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2018 Andrea Montefusco IW0HDV
+ *
+ * GNU Radio 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; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * config.h is generated by configure. It contains the results
+ * of probing for features, options etc. It should be the first
+ * file included in your .cc file.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdexcept>
+#include <iostream>
+#include <algorithm>
+
+#include <boost/assign.hpp>
+#include <boost/format.hpp>
+#include <boost/detail/endian.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <gnuradio/io_signature.h>
+
+#include "perseus_source_c.h"
+#include "arg_helpers.h"
+
+
+
+using namespace boost::assign;
+
+#define PERSEUS_FORMAT_ERROR(ret, msg) \
+ boost::str( boost::format(msg " (%1%)") % ret )
+
+#define PERSEUS_THROW_ON_ERROR(ret, msg) \
+ if ( ret != PERSEUS_NOERROR ) \
+ { \
+ throw std::runtime_error( PERSEUS_FORMAT_ERROR(ret, msg) ); \
+ }
+
+#define PERSEUS_FUNC_STR(func, arg) \
+ boost::str(boost::format(func "(%1%)") % arg) + " has failed"
+
+perseus_source_c_sptr make_perseus_source_c (const std::string & args)
+{
+ return gnuradio::get_initial_sptr(new perseus_source_c (args));
+}
+
+/*
+ * Specify constraints on number of input and output streams.
+ * This info is used to construct the input and output signatures
+ * (2nd & 3rd args to gr::block's constructor). The input and
+ * output signatures are used by the runtime system to
+ * check that a valid number and type of inputs and outputs
+ * are connected to this block. In this case, we accept
+ * only 0 input and 1 output.
+ */
+static const int MIN_IN = 0; // mininum number of input streams
+static const int MAX_IN = 0; // maximum number of input streams
+static const int MIN_OUT = 1; // minimum number of output streams
+static const int MAX_OUT = 1; // maximum number of output streams
+
+/*
+ * The private constructor
+ */
+perseus_source_c::perseus_source_c (const std::string &args)
+ : gr::sync_block ("perseus_source_c",
+ gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)),
+ gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))),
+ _dev(NULL),
+ _sample_rate(0),
+ _center_freq(0),
+ _freq_corr(0),
+ _frun(false),
+ _cnt(0),
+ _att_value(0),
+ _adc_preamp(false),
+ _adc_dither(false),
+ _preselector(false)
+{
+ dict_t dict = params_to_dict(args);
+
+ _dev = NULL;
+
+ // Set debug info dumped to stderr to the maximum verbose level
+ perseus_set_debug(3);
+
+ // Check how many Perseus receivers are connected to the system
+ int num_perseus = perseus_init();
+ std::cerr << "## Microtelecom Perseus ctor: " << num_perseus << " Perseus receivers found." << std::endl;
+
+ if (num_perseus==0) {
+ perseus_exit();
+ PERSEUS_THROW_ON_ERROR(PERSEUS_DEVNOTFOUND, "No Perseus receivers detected");
+ }
+ // Open the first one...
+ if ((_dev = perseus_open(0)) == NULL) {
+ PERSEUS_THROW_ON_ERROR(PERSEUS_DEVNOTFOUND, "Unable to open Perseus device");
+ }
+ // Download the standard firmware to the unit
+ std::cerr << "Downloading firmware..." << std::endl;
+ if (int rc = perseus_firmware_download(_dev,NULL)<0) {
+ PERSEUS_THROW_ON_ERROR (rc, "firmware download error");
+ }
+
+ // Dump some information about the receiver (S/N and HW rev)
+ int flag;
+ perseus_is_preserie(_dev, &flag);
+ if (flag != 0)
+ fprintf(stderr, "The device is a preserie unit");
+ else {
+ eeprom_prodid prodid;
+ if (perseus_get_product_id(_dev,&prodid)<0)
+ fprintf(stderr, "get product id error: %s", perseus_errorstr());
+ else
+ fprintf(stderr, "Receiver S/N: %05d-%02hX%02hX-%02hX%02hX-%02hX%02hX - HW Release:%hd.%hd\n",
+ (uint16_t) prodid.sn,
+ (uint16_t) prodid.signature[5],
+ (uint16_t) prodid.signature[4],
+ (uint16_t) prodid.signature[3],
+ (uint16_t) prodid.signature[2],
+ (uint16_t) prodid.signature[1],
+ (uint16_t) prodid.signature[0],
+ (uint16_t) prodid.hwrel,
+ (uint16_t) prodid.hwver);
+ }
+ // Printing all sampling rates available .....
+ {
+ int buf[BUFSIZ];
+
+ if (perseus_get_sampling_rates (_dev, buf, sizeof(buf)/sizeof(buf[0])) < 0) {
+ fprintf(stderr, "get sampling rates error: %s\n", perseus_errorstr());
+ } else {
+ int i = 0;
+ while (buf[i]) {
+ fprintf(stderr, "#%d: sample rate: %d\n", i, buf[i]);
+ _sample_rates.push_back( std::pair<double, uint32_t>( buf[i], i ) );
+ i++;
+ }
+ /* since they may (and will) give us an unsorted array we have to sort it here
+ * to play nice with the monotonic requirement of meta-range later on */
+ std::sort(_sample_rates.begin(), _sample_rates.end());
+
+ for (size_t i = 0; i < _sample_rates.size(); i++)
+ std::cerr << boost::format("%gM ") % (_sample_rates[i].first / 1e6);
+
+ std::cerr << std::endl;
+ }
+ }
+ // Configure the receiver for 2 MS/s operations
+ fprintf(stderr, "Configuring FPGA...\n");
+ if (int ret = perseus_set_sampling_rate(_dev, 96000) < 0) { // specify the sampling rate value in Samples/second
+ std::cerr << "fpga configuration error: " << perseus_errorstr() << std::endl;
+ PERSEUS_THROW_ON_ERROR(ret, "Perseus fpga configuration error");
+ }
+
+ perseus_set_attenuator_in_db(_dev, _att_value);
+ // Enable ADC Dither, Disable ADC Preamp
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ // set the NCO frequency in the middle of the range allowed
+ set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 );
+ set_sample_rate( get_sample_rates().start() );
+
+ _fifo = new boost::circular_buffer<gr_complex>(5000000);
+ if (!_fifo) {
+ throw std::runtime_error( std::string(__FUNCTION__) + " " +
+ "Failed to allocate a sample FIFO!" );
+ }
+}
+
+/*
+ * Our virtual destructor.
+ */
+perseus_source_c::~perseus_source_c ()
+{
+ if (_dev) {
+ if (_frun) stop();
+ int ret = perseus_close(_dev);
+ if ( ret != PERSEUS_NOERROR ) {
+ std::cerr << PERSEUS_FORMAT_ERROR(ret, "Failed to close Perseus") << std::endl;
+ } else
+ _dev = NULL;
+ }
+ perseus_exit();
+
+ if (_fifo) {
+ delete _fifo;
+ _fifo = NULL;
+ }
+}
+
+
+typedef union {
+ struct {
+ int32_t i;
+ int32_t q;
+ } __attribute__((__packed__)) iq;
+ struct {
+ uint8_t i1;
+ uint8_t i2;
+ uint8_t i3;
+ uint8_t i4;
+ uint8_t q1;
+ uint8_t q2;
+ uint8_t q3;
+ uint8_t q4;
+ } __attribute__((__packed__)) ;
+} iq_sample;
+
+
+int perseus_source_c::perseus_rx_callback(void *buf, int buf_size)
+{
+ size_t i, n_avail, to_copy, num_samples;
+
+ uint8_t *samplebuf = (uint8_t*)buf;
+
+ num_samples = buf_size/6;
+
+ if (buf_size % 6)
+ std::cerr << "FATAL !!!!!!! not on boundary" << std::endl;
+
+ iq_sample s;
+
+ _fifo_lock.lock();
+
+ n_avail = _fifo->capacity() - _fifo->size();
+ to_copy = (n_avail < num_samples ? n_avail : num_samples);
+
+ for (i = 0; i < to_copy; i++ ) {
+
+ s.i1 = s.q1 = 0;
+ s.i2 = *samplebuf++;
+ s.i3 = *samplebuf++;
+ s.i4 = *samplebuf++;
+ s.q2 = *samplebuf++;
+ s.q3 = *samplebuf++;
+ s.q4 = *samplebuf++;
+
+ // convert 24 bit two's complements integers to float in [-1.0 - +1.0] range
+ // Push sample to the fifo
+ _fifo->push_back( gr_complex( (float)(s.iq.i) / (INT_MAX - 256), (float)(s.iq.q) / (INT_MAX - 256) ) );
+
+ }
+ // keep a counter of processed bytes
+ _cnt += buf_size;
+
+ _fifo_lock.unlock();
+
+ /* We have made some new samples available to the consumer in work() */
+ if (to_copy) {
+ //std::cerr << "+" << std::flush;
+ _samp_avail.notify_one();
+ }
+
+ /* Indicate overrun, if necessary */
+ if (to_copy < num_samples)
+ std::cerr << "O" << std::flush;
+
+ return 0; // TODO: return -1 on error/stop
+}
+
+// static method used as callback from the libperseus-sdr library
+int perseus_source_c::_perseus_rx_callback(void *buf, int buf_size, void *extra)
+{
+ perseus_source_c *obj = (perseus_source_c *)extra;
+
+ return obj->perseus_rx_callback((float *)buf, buf_size);
+
+ return 0;
+}
+
+
+bool perseus_source_c::start()
+{
+ int ret;
+
+ if ( ! _dev )
+ return false;
+
+ std::cerr << "***** START COUNTER: " << _cnt
+ << " mod 6 " << (_cnt % 6) << std::endl;
+
+ _frun = true;
+
+ // in order to guarantee samples stream synchronization
+ // re-set the sample rate each time the stream is started
+ set_sample_rate( get_sample_rate() );
+
+ ret = perseus_start_async_input(_dev,
+ 6 * 1024 * 2 /* buffer size */,
+ perseus_source_c::_perseus_rx_callback,
+ (void *)this);
+ if (ret != PERSEUS_NOERROR) {
+ std::cerr << "Failed to start RX streaming ("
+ << ret << ")" << std::endl;
+ return false;
+ } else
+ return true;
+}
+
+bool perseus_source_c::stop()
+{
+ if ( ! _dev )
+ return false;
+
+ _frun = false;
+
+ std::cerr << "***** STOP COUNTER: " << _cnt
+ << " mod 6 " << (_cnt % 6) << std::endl;
+
+ int ret = perseus_stop_async_input(_dev);
+
+ if ( ret != PERSEUS_NOERROR ) {
+ std::cerr << "Failed to stop RX streaming (" << ret << ")" << std::endl;
+ return false;
+ } else
+ return true;
+}
+
+int perseus_source_c::work( int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items )
+{
+ gr_complex *out = (gr_complex *)output_items[0];
+
+ if ( _frun == false ) return WORK_DONE;
+
+ boost::unique_lock<boost::mutex> lock(_fifo_lock);
+
+ /* Wait until we have the requested number of samples */
+ int n_samples_avail = _fifo->size();
+
+ while (n_samples_avail < noutput_items) {
+ _samp_avail.wait(lock);
+ n_samples_avail = _fifo->size();
+ }
+
+ for(int i = 0; i < noutput_items; ++i) {
+ out[i] = _fifo->at(0);
+ _fifo->pop_front();
+ }
+
+ return noutput_items;
+}
+
+std::vector<std::string> perseus_source_c::get_devices()
+{
+ std::vector<std::string> devices;
+ std::string label;
+
+ std::string args = "perseus=0,label='Perseus'";
+ devices.push_back( args );
+
+ return devices;
+}
+
+size_t perseus_source_c::get_num_channels()
+{
+ return 1;
+}
+
+osmosdr::meta_range_t perseus_source_c::get_sample_rates()
+{
+ osmosdr::meta_range_t range;
+
+ for (size_t i = 0; i < _sample_rates.size(); i++) {
+ range += osmosdr::range_t( _sample_rates[i].first );
+ std::cerr << "SR: " << i << " : ("
+ << _sample_rates[i].first << ")" << std::endl;
+ }
+ return range;
+}
+
+double perseus_source_c::set_sample_rate( double rate )
+{
+ int ret;
+ if ((ret = perseus_set_sampling_rate(_dev, rate)) < 0) {
+ PERSEUS_THROW_ON_ERROR(ret, "Unable to set sample rate.");
+ } else
+ _sample_rate = rate;
+
+ return get_sample_rate();
+}
+
+double perseus_source_c::get_sample_rate()
+{
+ return _sample_rate;
+}
+
+osmosdr::freq_range_t perseus_source_c::get_freq_range( size_t chan )
+{
+ osmosdr::freq_range_t range;
+
+ range += osmosdr::range_t( PERSEUS_DDC_FREQ_MIN, PERSEUS_DDC_FREQ_MAX );
+
+ return range;
+}
+
+double perseus_source_c::set_center_freq( double freq, size_t chan )
+{
+ int ret;
+
+ if (_dev) {
+ ret =
+ perseus_set_ddc_center_freq(_dev,
+ (uint64_t)(freq * (1.0 + (_freq_corr * 10e-6))),
+ _preselector == true ? 1:0);
+ if ( ret == PERSEUS_NOERROR ) {
+ _center_freq = freq;
+ } else {
+ PERSEUS_THROW_ON_ERROR( ret, PERSEUS_FUNC_STR( "perseus_set_ddc_center_freq", freq ) )
+ }
+ }
+
+ return get_center_freq( chan );
+}
+
+double perseus_source_c::get_center_freq( size_t chan )
+{
+ return _center_freq;
+}
+
+double perseus_source_c::set_freq_corr( double ppm, size_t chan )
+{
+ return _freq_corr = ppm;
+}
+
+double perseus_source_c::get_freq_corr( size_t chan )
+{
+ return _freq_corr;
+}
+
+std::vector<std::string> perseus_source_c::get_gain_names( size_t chan )
+{
+ std::vector< std::string > names;
+
+ names += "Attenuator";
+ names += "ADC preamp";
+ names += "ADC dither";
+
+ return names;
+}
+
+//
+// FIXME
+//
+osmosdr::gain_range_t perseus_source_c::get_gain_range( size_t chan )
+{
+ return get_gain_range( "Attenuator", chan );
+}
+
+osmosdr::gain_range_t perseus_source_c::get_gain_range( const std::string & name, size_t chan )
+{
+ if ( "Attenuator" == name ) {
+ return osmosdr::gain_range_t( -30, 0, 10 );
+ }
+ if ( "ADC preamp" == name ) {
+ return osmosdr::gain_range_t( 0, 6, 6 );
+ }
+ if ( "ADC dither" == name ) {
+ return osmosdr::gain_range_t( 0, 1, 1 );
+ }
+
+ return osmosdr::gain_range_t();
+}
+
+
+double perseus_source_c::set_attenuator( double gain, size_t chan )
+{
+ int ret;
+
+ gain = - gain;
+ if (_dev && _att_value != gain) {
+ ret = perseus_set_attenuator_in_db (_dev, gain);
+
+ if ( PERSEUS_NOERROR == ret ) {
+ _att_value = gain;
+ } else {
+ std::cerr << "ERROR: perseus_set_attenuator_in_db: " << gain << std::endl;
+ }
+ }
+
+ return _att_value;
+}
+
+double perseus_source_c::set_adc_preamp( double gain, size_t chan )
+{
+ std::cerr << "set_adc_preamp: " << gain << std::endl;
+
+ if (_dev) {
+ _adc_preamp = (gain != 0. ? true : false);
+ int ret =
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ if ( PERSEUS_NOERROR != ret ) {
+ std::cerr << "ERROR: perseus_set_adc" << ret << std::endl;
+ }
+ }
+ return gain;
+}
+
+double perseus_source_c::set_adc_dither( double gain, size_t chan )
+{
+ std::cerr << "set_adc_dither: " << gain << std::endl;
+
+ if (_dev) {
+ _adc_dither = (gain != 0. ? true : false);
+ int ret =
+ perseus_set_adc(_dev, _adc_dither == true ? 1:0, _adc_preamp == true ? 1:0);
+ if ( PERSEUS_NOERROR != ret ) {
+ std::cerr << "ERROR: perseus_set_adc" << ret << std::endl;
+ }
+ }
+ return gain;
+}
+
+double perseus_source_c::get_attenuator( size_t chan )
+{
+ return _att_value;
+}
+
+double perseus_source_c::get_adc_preamp(size_t chan )
+{
+ double v = _adc_preamp == true ? 6. : 0.;
+ std::cerr << "get_adc_preamp: " << _adc_preamp << " value" << v << std::endl;
+ return v;
+}
+
+double perseus_source_c::get_adc_dither(size_t chan )
+{
+ double v = _adc_dither == true ? 1. : 0.;
+ std::cerr << "get_adc_dither: " << _adc_dither << " value" << v << std::endl;
+ return v;
+}
+
+
+double perseus_source_c::set_gain( double gain, const std::string & name, size_t chan)
+{
+ if ( "Attenuator" == name ) {
+ return set_attenuator( gain, chan );
+ }
+ if ( "ADC preamp" == name ) {
+ return set_adc_preamp( gain, chan );
+ }
+ if ( "ADC dither" == name ) {
+ return set_adc_dither( gain, chan );
+ }
+ return gain;
+}
+
+
+double perseus_source_c::get_gain( const std::string & name, size_t chan )
+{
+ if ( "Attenuator" == name ) {
+ return get_attenuator( chan );
+ }
+ if ( "ADC preamp" == name ) {
+ return get_adc_preamp( chan );
+ }
+ if ( "ADC dither" == name ) {
+ return get_adc_dither( chan );
+ }
+ return 0.0;
+}
+
+
+
+std::vector< std::string > perseus_source_c::get_antennas( size_t chan )
+{
+ std::vector< std::string > antennas;
+
+ antennas += "RX";
+ antennas += "RX+PRESELECTOR";
+
+ return antennas;
+}
+
+std::string perseus_source_c::set_antenna( const std::string & antenna, size_t chan )
+{
+ if ( antenna == "RX" ) {
+ _preselector = false;
+ set_center_freq( get_center_freq() );
+ return "RX";
+ }
+ if ( antenna == "RX+PRESELECTOR" ) {
+ _preselector = true;
+ set_center_freq( get_center_freq() );
+ return "RX+PRESELECTOR";
+ }
+ return get_antenna( chan );
+}
+
+std::string perseus_source_c::get_antenna( size_t chan )
+{
+ std::cerr << "perseus_source_c::get_antenna: " << chan << std::endl;
+ return "RX";
+}
diff --git a/lib/perseus/perseus_source_c.h b/lib/perseus/perseus_source_c.h
new file mode 100644
index 0000000..55d3f89
--- /dev/null
+++ b/lib/perseus/perseus_source_c.h
@@ -0,0 +1,135 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Dimitri Stolnikov <horiz0n(a)gmx.net>
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio 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; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef INCLUDED_PERSEUS_SOURCE_C_H
+#define INCLUDED_PERSEUS_SOURCE_C_H
+
+#include <boost/circular_buffer.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+
+#include <gnuradio/sync_block.h>
+
+#include "source_iface.h"
+#include <perseus-sdr.h>
+
+class perseus_source_c;
+
+typedef boost::shared_ptr<perseus_source_c> perseus_source_c_sptr;
+
+/*!
+ * \brief Return a shared_ptr to a new instance of perseus_source_c.
+ *
+ * To avoid accidental use of raw pointers, perseus_source_c's
+ * constructor is private. make_perseus_source_c is the public
+ * interface for creating new instances.
+ */
+perseus_source_c_sptr make_perseus_source_c (const std::string & args = "");
+
+/*!
+ * \brief Provides a stream of complex samples.
+ * \ingroup block
+ */
+class perseus_source_c :
+ public gr::sync_block,
+ public source_iface
+{
+private:
+ // The friend declaration allows make_perseus_source_c to
+ // access the private constructor.
+
+ friend perseus_source_c_sptr make_perseus_source_c (const std::string & args);
+
+ perseus_source_c (const std::string & args);
+
+public:
+ ~perseus_source_c ();
+
+ bool start();
+ bool stop();
+
+ int work( int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items );
+
+ static std::vector< std::string > get_devices();
+
+ size_t get_num_channels( void );
+
+ osmosdr::meta_range_t get_sample_rates( void );
+ double set_sample_rate( double rate );
+ double get_sample_rate( void );
+
+ osmosdr::freq_range_t get_freq_range( size_t chan = 0 );
+ double set_center_freq( double freq, size_t chan = 0 );
+ double get_center_freq( size_t chan = 0 );
+ double set_freq_corr( double ppm, size_t chan = 0 );
+ double get_freq_corr( size_t chan = 0 );
+
+ std::vector<std::string> get_gain_names( size_t chan = 0 );
+ osmosdr::gain_range_t get_gain_range( size_t chan = 0 );
+ osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 );
+
+ double set_gain( double gain, size_t chan = 0 ) {return gain; }
+ double get_gain( size_t chan = 0 ) {return _att_value; }
+
+ double set_attenuator( double gain, size_t chan = 0 );
+ double get_attenuator( size_t chan = 0 );
+
+ double set_adc_preamp( double gain, size_t chan = 0 );
+ double get_adc_preamp( size_t chan = 0 );
+
+ double set_adc_dither( double gain, size_t chan = 0 );
+ double get_adc_dither( size_t chan = 0 );
+
+ double set_gain( double gain, const std::string & name, size_t chan = 0 );
+ double get_gain( const std::string & name, size_t chan = 0 );
+
+ std::vector< std::string > get_antennas( size_t chan = 0 );
+ std::string set_antenna( const std::string & antenna, size_t chan = 0 );
+ std::string get_antenna( size_t chan = 0 );
+
+
+private:
+ static int _perseus_rx_callback(void *buf, int buf_size, void *extra);
+
+ int perseus_rx_callback(void *samples, int sample_count);
+
+ perseus_descr *_dev;
+
+ boost::circular_buffer<gr_complex> *_fifo;
+ boost::mutex _fifo_lock;
+ boost::condition_variable _samp_avail;
+
+ std::vector< std::pair<double, uint32_t> > _sample_rates;
+ double _sample_rate;
+ double _center_freq;
+ double _freq_corr;
+
+ bool _frun;
+ int _cnt;
+ double _att_value;
+ bool _adc_preamp;
+ bool _adc_dither;
+ bool _preselector;
+};
+
+#endif /* INCLUDED_PERSEUS_SOURCE_C_H */
diff --git a/lib/source_impl.cc b/lib/source_impl.cc
index a28f314..ead4ef7 100644
--- a/lib/source_impl.cc
+++ b/lib/source_impl.cc
@@ -92,6 +92,9 @@
#include <freesrp_source_c.h>
#endif
+#ifdef ENABLE_PERSEUS
+#include <perseus_source_c.h>
+#endif
#include "arg_helpers.h"
#include "source_impl.h"
@@ -171,6 +174,9 @@ source_impl::source_impl( const std::string &args )
#ifdef ENABLE_FREESRP
dev_types.push_back("freesrp");
#endif
+#ifdef ENABLE_PERSEUS
+ dev_types.push_back("perseus");
+#endif
std::cerr << "gr-osmosdr "
<< GR_OSMOSDR_VERSION << " (" << GR_OSMOSDR_LIBVER << ") "
<< "gnuradio " << gr::version() << std::endl;
@@ -252,7 +258,10 @@ source_impl::source_impl( const std::string &args )
BOOST_FOREACH( std::string dev, freesrp_source_c::get_devices() )
dev_list.push_back( dev );
#endif
-
+#ifdef ENABLE_PERSEUS
+ BOOST_FOREACH( std::string dev, perseus_source_c::get_devices() )
+ dev_list.push_back( dev );
+#endif
// std::cerr << std::endl;
// BOOST_FOREACH( std::string dev, dev_list )
// std::cerr << "'" << dev << "'" << std::endl;
@@ -383,6 +392,13 @@ source_impl::source_impl( const std::string &args )
}
#endif
+#ifdef ENABLE_PERSEUS
+ if ( dict.count("perseus") ) {
+ perseus_source_c_sptr src = make_perseus_source_c( arg );
+ block = src; iface = src.get();
+ }
+#endif
+
if ( iface != NULL && long(block.get()) != 0 ) {
_devs.push_back( iface );
--
1.9.1
3
2
03 Aug '18
Good afternoon everyone.
I write here to see if any of you know that installation errors I may have had to use the r820t2 in gnu radio companion.
I'm trying to make an FM receiver and other analog TV receiver but when running the program does not receive any type of signal and the view errors, I have: devices not supported. I believe that this is some driver to be installed but I don't know where or how.
The steps that I have followed for installation (Ubuntu 16.04 LTS) have been:
1. Install gnuradio.
2. Install Xenial Xerius specifications (it is supposed to do I need for my version of Ubuntu).
I3. nstall specifications of gr-osmosdr to enable some features of the chip.
The Stick comes with a CD but i do not know how to install it since, according to the specifications only works for WXP, 2000, Vista, 7 and 8; and it is something that it seems strange to me since I have seen videos where they use this same model of stick to carry out projects in Gnuradio on Ubuntu.
I tried with this:
sudo apt-get update
sudo apt-get install git
sudo apt-get install cmake
sudo apt-get install build-essential
sudo apt-get install libusb-1.0-0-dev
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr/
mkdir build
cd build
cmake ../ -DINSTALL_UDEV_RULES=ON
make
sudo make install
sudo ldconfig
sudo cp ../rtl-sdr.rules /etc/udev/rules.d/
Opening /etc/modprobe.d folder
Creating a new file 'blacklist-rtl.conf' and add this one line:
blacklist dvb_usb_rtl28xxu
rtl_test -t
I tried those commands but I do not know if I need to install something else because GNRC still says: "FATAL: No supported devices found to pick from"...
Please, if any of you know that i need to install It would serve as much help as I am a novice programmer and i need to resolve this problem for my project.
Enviado desde Outlook<http://aka.ms/weboutlook>
1
0
Hello,
I hope you are well.
I am looking to commission an array of GPS units that emulate the standard
GPS.
This is to provide positioning service indoors and underground in a large
open space.
Can you help with something like this?
Kindest regards,
Mike
*Mike Bishop*
Operations Director
Spider UAS Operations Ltd
CAA Authorised UAV Operator
M: 07801 450 392
***SHOWREEL***
<http://t.sidekickopen08.com/e1t/c/5/f18dQhb0S7lC8dDMPbW2n0x6l2B9nMJW7t5XZs4…>
E: Mike(a)spideraerialfilming.com
W: spideraerialfilming.com
W: dronebuilders.co.uk
Instagram: Spider_Drone
<http://t.sidekickopen08.com/e1t/c/5/f18dQhb0S7lC8dDMPbW2n0x6l2B9nMJW7t5XZs4…>
1
0