Adding new Ad936x custom signal source, initial commit, experimental

This commit is contained in:
Javier Arribas 2022-08-14 12:10:59 +02:00
parent d31f0c39dc
commit 6311530cb4
16 changed files with 2405 additions and 79 deletions

View File

@ -21,6 +21,12 @@ if(ENABLE_PLUTOSDR)
##############################################
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} plutosdr_signal_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} plutosdr_signal_source.h)
##############################################
# CUSTOM AD936X IIO SOURCE
##############################################
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_custom_signal_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_custom_signal_source.h)
endif()

View File

@ -0,0 +1,325 @@
/*!
* \file ad936x_custom_signal_source.cc
* \brief A direct IIO custom front-end gnss-sdr signal source for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ad936x_custom_signal_source.h"
#include "configuration_interface.h"
#include "gnss_frequencies.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <boost/exception/diagnostic_information.hpp>
#include <glog/logging.h>
#include <gnuradio/blocks/file_sink.h>
#include <iostream>
using namespace std::string_literals;
Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_stream,
unsigned int out_stream,
Concurrent_Queue<pmt::pmt_t>* queue __attribute__((unused)))
: SignalSourceBase(configuration, role, "Ad936x_Custom_Signal_Source"s),
in_stream_(in_stream),
out_stream_(out_stream),
item_type_(configuration->property(role + ".item_type", std::string("gr_complex"))),
samples_(configuration->property(role + ".samples", int64_t(0))),
dump_(configuration->property(role + ".dump", false)),
dump_filename_(configuration->property(role + ".dump_filename", std::string("./data/signal_source.dat"))),
pluto_uri_(configuration->property(role + ".pluto_uri", std::string("local"))),
board_type_(configuration->property(role + ".board_type", std::string("single_ad9361"))),
sample_rate_(configuration->property(role + ".sampling_frequency", 4.0e6)),
bandwidth_(configuration->property(role + ".bandwidth", configuration->property(role + ".sampling_frequency", 4.0e6) / 1.1)),
freq_(configuration->property(role + ".freq", FREQ1)),
freq_2ch(configuration->property(role + ".freq_2ch", FREQ1)),
rf_port_select_(configuration->property(role + ".rf_port_select", std::string("A_BALANCED"))),
rf_filter(configuration->property(role + ".rf_filter", std::string("none"))),
gain_mode_rx0_(configuration->property(role + ".gain_mode_rx0", std::string("slow_attack"))),
gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", std::string("slow_attack"))),
rf_gain_rx0_(configuration->property(role + ".gain_rx0", 40.0)),
rf_gain_rx1_(configuration->property(role + ".gain_rx1", 40.0)),
enable_ch0(configuration->property(role + ".enable_ch0", true)),
enable_ch1(configuration->property(role + ".enable_ch1", false)),
PPS_mode_(configuration->property(role + ".PPS_mode", false)),
fe_ip_(configuration->property(role + ".fe_ip", std::string("192.168.2.1"))),
fe_ctlport_(configuration->property(role + ".fe_ctlport", int32_t(10000))),
ssize_(configuration->property(role + ".ssize", int32_t(16))),
bshift_(configuration->property(role + ".bshift", int64_t(0))),
spattern_(configuration->property(role + ".spattern", false)),
inverted_spectrum_ch0_(configuration->property(role + ".inverted_spectrum_ch0", false)),
inverted_spectrum_ch1_(configuration->property(role + ".inverted_spectrum_ch1", false))
{
if (item_type_ == "gr_complex")
{
item_size_ = sizeof(gr_complex);
// 1. Make the driver instance
bool customsamplesize = false;
if (ssize_ != 16 or spattern_ == true) customsamplesize = true;
ad936x_iio_source = ad936x_iio_make_source_sptr(
pluto_uri_,
board_type_,
bandwidth_,
sample_rate_,
freq_,
rf_port_select_,
rf_filter,
gain_mode_rx0_,
gain_mode_rx1_,
rf_gain_rx0_,
rf_gain_rx1_,
enable_ch0,
enable_ch1,
freq_2ch,
PPS_mode_,
customsamplesize,
fe_ip_,
fe_ctlport_,
ssize_,
bshift_,
spattern_);
n_channels = 1;
if (enable_ch0 == true and enable_ch1 == true)
{
n_channels = 2;
}
for (int n = 0; n < n_channels; n++)
{
if (ssize_ == 16)
{
gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make());
}
else if (ssize_ == 8)
{
gr_interleaved_char_to_complex_.push_back(gr::blocks::interleaved_char_to_complex::make());
}
else if (ssize_ == 4)
{
gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, false));
unpack_byte_fourbits.push_back(make_unpack_byte_4bit_samples());
}
else if (ssize_ == 2)
{
gr_interleaved_short_to_complex_.push_back(gr::blocks::interleaved_short_to_complex::make(false, false));
unpack_byte_twobits.push_back(make_unpack_byte_2bit_cpx_samples());
}
}
}
else
{
LOG(ERROR) << item_type_ << " unrecognized item type";
exit(1);
}
if (dump_)
{
for (int n = 0; n < n_channels; n++)
{
DLOG(INFO) << "Dumping output into file " << (dump_filename_ + "c_h" + std::to_string(n) + ".bin");
sink_.emplace_back(gr::blocks::file_sink::make(item_size_, (dump_filename_ + "_ch" + std::to_string(n) + ".bin").c_str()));
}
}
if (in_stream_ > 0)
{
LOG(ERROR) << "A signal source does not have an input stream";
}
if (out_stream_ > 1)
{
LOG(ERROR) << "This implementation only supports one output stream";
}
}
void Ad936xCustomSignalSource::connect(gr::top_block_sptr top_block)
{
for (int n = 0; n < n_channels; n++)
{
if (ssize_ == 16)
{
top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else if (ssize_ == 8)
{
top_block->connect(ad936x_iio_source, n, gr_interleaved_char_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_char_to_complex_ for channel " << n;
if (dump_)
{
top_block->connect(gr_interleaved_char_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else if (ssize_ == 4)
{
top_block->connect(ad936x_iio_source, n, unpack_byte_fourbits.at(n), 0);
top_block->connect(unpack_byte_fourbits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else if (ssize_ == 2)
{
top_block->connect(ad936x_iio_source, n, unpack_byte_twobits.at(n), 0);
top_block->connect(unpack_byte_twobits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else
{
top_block->connect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
}
void Ad936xCustomSignalSource::disconnect(gr::top_block_sptr top_block)
{
for (int n = 0; n < n_channels; n++)
{
if (ssize_ == 16)
{
top_block->disconnect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else if (ssize_ == 8)
{
top_block->disconnect(ad936x_iio_source, n, gr_interleaved_char_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_char_to_complex_ for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_char_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else if (ssize_ == 4)
{
top_block->disconnect(ad936x_iio_source, n, unpack_byte_fourbits.at(n), 0);
top_block->disconnect(unpack_byte_fourbits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (dump_)
{
top_block->connect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else if (ssize_ == 2)
{
top_block->disconnect(ad936x_iio_source, n, unpack_byte_twobits.at(n), 0);
top_block->disconnect(unpack_byte_twobits.at(n), 0, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to unpack_byte_fourbits for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
else
{
top_block->disconnect(ad936x_iio_source, n, gr_interleaved_short_to_complex_.at(n), 0);
DLOG(INFO) << "connected ad936x_iio_source source to gr_interleaved_short_to_complex for channel " << n;
if (dump_)
{
top_block->disconnect(gr_interleaved_short_to_complex_.at(n), 0, sink_.at(n), 0);
DLOG(INFO) << "connected source to file sink";
}
}
}
}
gr::basic_block_sptr Ad936xCustomSignalSource::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
return {};
}
gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block()
{
if (ssize_ == 16)
{
return gr_interleaved_short_to_complex_.at(0);
}
else if (ssize_ == 8)
{
return gr_interleaved_char_to_complex_.at(0);
}
else if (ssize_ == 4)
{
return gr_interleaved_short_to_complex_.at(0);
}
else if (ssize_ == 2)
{
return gr_interleaved_short_to_complex_.at(0);
}
else
{
return gr_interleaved_short_to_complex_.at(0);
}
}
gr::basic_block_sptr Ad936xCustomSignalSource::get_right_block(int RF_channel)
{
if (ssize_ == 16)
{
return gr_interleaved_short_to_complex_.at(RF_channel);
}
else if (ssize_ == 8)
{
return gr_interleaved_char_to_complex_.at(RF_channel);
}
else if (ssize_ == 4)
{
return gr_interleaved_short_to_complex_.at(RF_channel);
}
else if (ssize_ == 2)
{
return gr_interleaved_short_to_complex_.at(RF_channel);
}
else
{
return gr_interleaved_short_to_complex_.at(RF_channel);
}
}

View File

@ -0,0 +1,118 @@
/*!
* \file ad936x_custom_signal_source.h
* \brief A direct IIO custom front-end gnss-sdr signal source for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H
#define GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H
#include "ad936x_iio_source.h"
#include "concurrent_queue.h"
#include "conjugate_cc.h"
#include "signal_source_base.h"
#include "unpack_byte_2bit_cpx_samples.h"
#include "unpack_byte_4bit_samples.h"
#include <gnuradio/blocks/file_sink.h>
#include <gnuradio/blocks/interleaved_char_to_complex.h>
#include <gnuradio/blocks/interleaved_short_to_complex.h>
#include <pmt/pmt.h>
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
class ConfigurationInterface;
/*!
* \brief This class instantiates the Ad936xCustom gnuradio signal source.
* It has support also for a customized Ad936xCustom firmware and signal source to support PPS samplestamp reading.
*/
class Ad936xCustomSignalSource : public SignalSourceBase
{
public:
Ad936xCustomSignalSource(const ConfigurationInterface* configuration,
const std::string& role, unsigned int in_stream,
unsigned int out_stream, Concurrent_Queue<pmt::pmt_t>* queue);
~Ad936xCustomSignalSource() = default;
inline size_t item_size() override
{
return item_size_;
}
void connect(gr::top_block_sptr top_block) override;
void disconnect(gr::top_block_sptr top_block) override;
gr::basic_block_sptr get_left_block() override;
gr::basic_block_sptr get_right_block() override;
gr::basic_block_sptr get_right_block(int RF_channel) override;
private:
unsigned int in_stream_;
unsigned int out_stream_;
gr::block_sptr ad936x_iio_source;
std::vector<gr::blocks::file_sink::sptr> sink_;
std::vector<std::string> filename_vec_;
std::vector<gr::blocks::interleaved_short_to_complex::sptr> gr_interleaved_short_to_complex_;
std::vector<gr::blocks::interleaved_char_to_complex::sptr> gr_interleaved_char_to_complex_;
std::vector<unpack_byte_4bit_samples_sptr> unpack_byte_fourbits;
std::vector<unpack_byte_2bit_cpx_samples_sptr> unpack_byte_twobits;
std::string item_type_;
size_t item_size_;
int64_t samples_;
bool dump_;
std::string dump_filename_;
// Front-end settings
std::string pluto_uri_;
std::string board_type_;
long long sample_rate_;
long long bandwidth_;
long long freq_;
long long freq_2ch;
std::string rf_port_select_;
std::string rf_filter;
std::string gain_mode_rx0_;
std::string gain_mode_rx1_;
double rf_gain_rx0_;
double rf_gain_rx1_;
bool enable_ch0;
bool enable_ch1;
bool PPS_mode_;
std::string fe_ip_;
int fe_ctlport_;
int ssize_;
int bshift_;
bool spattern_;
bool inverted_spectrum_ch0_;
bool inverted_spectrum_ch1_;
int n_channels;
};
/** \} */
/** \} */
#endif // GNSS_SDR_Ad936xCustom_SIGNAL_SOURCE_H

View File

@ -17,6 +17,13 @@ if(ENABLE_AD936X_SDR)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gr_complex_ip_packet_source.h)
endif()
if(ENABLE_PLUTOSDR)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_iio_source.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_iio_source.h)
endif()
set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
fifo_reader.cc
unpack_byte_2bit_samples.cc

View File

@ -1,16 +1,14 @@
/*!
* \file ad936x_iio_source.cc
*
* \brief Unpacks capture files in the LabSat 2 (ls2), LabSat 3 (ls3), or LabSat
* 3 Wideband (LS3W) formats.
* \author Javier Arribas jarribas (at) cttc.es
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
@ -19,12 +17,13 @@
#include "ad936x_iio_source.h"
#include "INIReader.h"
#include "ad936x_iio_samples.h"
#include "command_event.h"
#include "gnss_sdr_make_unique.h"
#include "pps_samplestamp.h"
#include <gnuradio/io_signature.h>
#include <algorithm>
#include <array>
#include <bitset>
#include <exception>
#include <iomanip>
#include <iostream>
@ -33,64 +32,245 @@
#include <utility>
ad936x_iio_source_sptr ad936x_iio_make_source_sptr(Concurrent_Queue<pmt::pmt_t> *queue,
std::string pluto_device_uri,
std::string board_type,
ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
std::vector<std::string> ch_list,
std::vector<std::string> ch_gain_mode,
std::vector<double> ch_gain_db,
std::vector<long int> ch_freq_hz,
int ch_sample_size,
int ch_sample_bits_shift)
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_)
{
return ad936x_iio_source_sptr(new ad936x_iio_source(*queue,
pluto_device_uri,
board_type,
return ad936x_iio_source_sptr(new ad936x_iio_source(
pluto_uri_,
board_type_,
bandwidth_,
sample_rate_,
ch_list,
ch_gain_mode,
ch_gain_db,
ch_freq_hz,
ch_sample_size,
ch_sample_bits_shift));
freq_,
rf_port_select_,
rf_filter,
gain_mode_rx0_,
gain_mode_rx1_,
rf_gain_rx0_,
rf_gain_rx1_,
enable_ch0,
enable_ch1,
freq_2ch,
ppsmode_,
customsamplesize_,
fe_ip_,
fe_ctlport_,
ssize_,
bshift_,
spattern_));
}
ad936x_iio_source::ad936x_iio_source(Concurrent_Queue<pmt::pmt_t> *queue,
std::string pluto_device_uri,
std::string board_type,
ad936x_iio_source::ad936x_iio_source(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
std::vector<std::string> ch_list,
std::vector<std::string> ch_gain_mode,
std::vector<double> ch_gain_db,
std::vector<long int> ch_freq_hz,
int ch_sample_size,
int ch_sample_bits_shift) : gr::block("ad936x_iio_source",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(1, 3, sizeof(gr_complex)))
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_) : gr::block("ad936x_iio_source",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(1, 4, sizeof(int16_t)))
{
}
ad936x_custom = std::make_unique<ad936x_iio_custom>(0, 0);
try
{
if (ad936x_custom->initialize_device(pluto_uri_, board_type_) == true)
{
//configure channels
if (ad936x_custom->init_config_ad9361_rx(bandwidth_,
sample_rate_,
freq_,
rf_port_select_,
rf_filter,
gain_mode_rx0_,
gain_mode_rx1_,
rf_gain_rx0_,
rf_gain_rx1_,
enable_ch0,
enable_ch1,
freq_2ch) == true)
{
std::cout << "ad936x_iio_source HW configured OK!\n";
//PPS FPGA Samplestamp information from TCP server
pps_rx = std::make_shared<pps_tcp_rx>();
ppsqueue = std::shared_ptr<Concurrent_Queue<PpsSamplestamp>>(new Concurrent_Queue<PpsSamplestamp>());
pps_rx->set_pps_samplestamp_queue(ppsqueue);
ad936x_custom->set_pps_samplestamp_queue(ppsqueue);
//start PPS RX thread
if (ppsmode_ == true or customsamplesize_ == true)
{
pps_rx_thread = std::thread(&pps_tcp_rx::receive_pps, pps_rx, fe_ip_, fe_ctlport_);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
//configure custom FPGA options
switch (ssize_)
{
case 16:
{
std::cout << "FPGA sample size set to 16 bits per sample.\n";
if (pps_rx->send_cmd("ssize=16\n") == false) std::cout << "cmd send error!\n";
break;
}
case 8:
{
std::cout << "FPGA sample size set to 8 bits per sample.\n";
if (pps_rx->send_cmd("ssize=8\n") == false) std::cout << "cmd send error!\n";
break;
}
case 4:
{
std::cout << "FPGA sample size set to 4 bits per sample.\n";
if (pps_rx->send_cmd("ssize=4\n") == false) std::cout << "cmd send error!\n";
break;
}
case 2:
{
std::cout << "FPGA sample size set to 2 bits per sample.\n";
if (pps_rx->send_cmd("ssize=2\n") == false) std::cout << "cmd send error!\n";
break;
}
default:
{
std::cout << "WARNING: Unsupported ssize. FPGA sample size set to 16 bits per sample.\n";
if (pps_rx->send_cmd("ssize=16") == false) std::cout << "cmd send error!\n";
}
}
if (bshift_ >= 0 and bshift_ <= 14)
{
std::cout << "FPGA sample bits shift left set to " + std::to_string(bshift_) + " positions.\n";
if (pps_rx->send_cmd("bshift=" + std::to_string(bshift_) + "\n") == false) std::cout << "cmd send error!\n";
}
else
{
std::cout << "WARNING: Unsupported bshift. FPGA sample bits shift left set to 0.\n";
if (pps_rx->send_cmd("bshift=0\n") == false) std::cout << "cmd send error!\n";
}
if (spattern_ == true)
{
std::cout << "FPGA debug sample pattern is active!.\n";
if (pps_rx->send_cmd("spattern=1\n") == false) std::cout << "cmd send error!\n";
}
else
{
std::cout << "FPGA debug sample pattern disabled.\n";
if (pps_rx->send_cmd("spattern=0\n") == false) std::cout << "cmd send error!\n";
}
}
else
{
std::cout << "PPS mode NOT enabled, not configuring PlutoSDR custom timestamping FPGA IP.\n";
}
}
else
{
std::cerr << "ad936x_iio_source IIO initialization error." << std::endl;
exit(1);
}
}
else
{
std::cerr << "ad936x_iio_source IIO initialization error." << std::endl;
exit(1);
}
}
catch (std::exception const &ex)
{
std::cerr << "STD exception: " << ex.what() << std::endl;
exit(1);
}
catch (...)
{
std::cerr << "Unexpected catch" << std::endl;
exit(1);
}
//set_min_noutput_items(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2);
set_min_output_buffer(IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2);
//std::cout << "max_output_buffer " << min_output_buffer(0) << " min_noutput_items: " << min_noutput_items() << "\n";
}
ad936x_iio_source::~ad936x_iio_source()
{
// Terminate PPS thread
if (pps_rx_thread.joinable())
{
pthread_t id = pps_rx_thread.native_handle();
pps_rx_thread.detach();
pthread_cancel(id);
}
}
bool ad936x_iio_source::start()
{
return ad936x_custom->start_sample_rx(false);
}
bool ad936x_iio_source::stop()
{
ad936x_custom->stop_record();
return true;
}
int ad936x_iio_source::general_work(int noutput_items,
__attribute__((unused)) gr_vector_int &ninput_items,
__attribute__((unused)) gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
std::vector<gr_complex *> out;
for (auto &output_item : output_items)
std::shared_ptr<ad936x_iio_samples> current_buffer;
ad936x_iio_samples *current_samples;
ad936x_custom->pop_sample_buffer(current_buffer);
current_samples = current_buffer.get();
//I and Q samples are interleaved in buffer: IQIQIQ...
for (size_t n = 0; n < ad936x_custom->n_channels; n++)
{
out.push_back(reinterpret_cast<gr_complex *>(output_item));
if (output_items.size() > n) // check if the output channel is connected
{
memcpy(reinterpret_cast<void *>(output_items[n]), reinterpret_cast<void *>(current_samples->buffer[n]), current_samples->n_bytes[n]);
produce(n, current_samples->n_samples[n]);
}
}
std::cout << "Warning!!\n";
return 0;
ad936x_custom->push_sample_buffer(current_buffer);
return this->WORK_CALLED_PRODUCE;
}

View File

@ -1,8 +1,7 @@
/*!
* \file ad936x_iio_source.h
*
* \brief signal source to receive samples from the AD936x FE family over libiio, including special custom functionalities in FPGA firmware.
* \author Javier Arribas jarribas (at) cttc.es
* \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
@ -15,19 +14,22 @@
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_AD9361_IIO_SOURCE_H
#define GNSS_SDR_AD9361_IIO_SOURCE_H
#ifndef GNSS_SDR_AD936X_IIO_SOURCE_H
#define GNSS_SDR_AD936X_IIO_SOURCE_H
#include "ad936x_iio_custom.h"
#include "concurrent_queue.h"
#include "gnss_block_interface.h"
#include "ppstcprx.h"
#include <gnuradio/block.h>
#include <iio.h>
#include <pmt/pmt.h>
#include <ad9361.h> //multichip sync and high level functions
#include <cstddef>
#include <cstdint>
#include <fstream>
#include <memory>
#include <string>
#include <thread>
#include <vector>
/** \addtogroup Signal_Source
@ -41,17 +43,27 @@ class ad936x_iio_source;
using ad936x_iio_source_sptr = gnss_shared_ptr<ad936x_iio_source>;
ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
Concurrent_Queue<pmt::pmt_t> *queue,
std::string pluto_device_uri,
std::string board_type,
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
std::vector<std::string> ch_list,
std::vector<std::string> ch_gain_mode,
std::vector<double> ch_gain_db,
std::vector<long int> ch_freq_hz,
int ch_sample_size,
int ch_sample_bits_shift);
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_);
/*!
* \brief This class implements conversion between Labsat 2, 3 and 3 Wideband
@ -62,6 +74,11 @@ class ad936x_iio_source : public gr::block
public:
~ad936x_iio_source();
//! start the sample transmission
bool start();
//! stop the sample transmission
bool stop();
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
@ -69,32 +86,60 @@ public:
private:
friend ad936x_iio_source_sptr ad936x_iio_make_source_sptr(
Concurrent_Queue<pmt::pmt_t> *queue,
std::string pluto_device_uri,
std::string board_type,
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
std::vector<std::string> ch_list,
std::vector<std::string> ch_gain_mode,
std::vector<double> ch_gain_db,
std::vector<long int> ch_freq_hz,
int ch_sample_size,
int ch_sample_bits_shift);
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_);
ad936x_iio_source(Concurrent_Queue<pmt::pmt_t> *queue,
std::string pluto_device_uri,
std::string board_type,
ad936x_iio_source(
std::string pluto_uri_,
std::string board_type_,
long long bandwidth_,
long long sample_rate_,
std::vector<std::string> ch_list,
std::vector<std::string> ch_gain_mode,
std::vector<double> ch_gain_db,
std::vector<long int> ch_freq_hz,
int ch_sample_size,
int ch_sample_bits_shift);
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch,
bool ppsmode_,
bool customsamplesize_,
std::string fe_ip_,
int fe_ctlport_,
int ssize_,
int bshift_,
bool spattern_);
std::thread pps_rx_thread;
std::unique_ptr<ad936x_iio_custom> ad936x_custom;
std::shared_ptr<pps_tcp_rx> pps_rx;
std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> ppsqueue;
};
/** \} */
/** \} */
#endif // GNSS_SDR_AD9361_IIO_SOURCE_H
#endif // GNSS_SDR_AD936X_IIO_SOURCE_H

View File

@ -8,8 +8,8 @@
set(OPT_SIGNAL_SOURCE_LIB_SOURCES "")
set(OPT_SIGNAL_SOURCE_LIB_HEADERS "")
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ad9361_manager.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ad9361_manager.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h)
endif()
if(ENABLE_FPGA OR ENABLE_AD9361)
@ -23,6 +23,18 @@ if(ENABLE_FPGA OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma.h)
endif()
if(ENABLE_PLUTOSDR)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} pps_samplestamp.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.h)
endif()
set(SIGNAL_SOURCE_LIB_SOURCES
rtl_tcp_commands.cc
rtl_tcp_dongle_info.cc
@ -88,7 +100,7 @@ if(GNURADIO_USES_SPDLOG)
)
endif()
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361 OR ENABLE_PLUTOSDR)
target_link_libraries(signal_source_libs
PUBLIC
Iio::iio

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
/*!
* \file ad936x_iio_custom.h
* \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities.
* \author Javier Arribas, jarribas(at)cttc.es
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef SRC_LIBS_ad936x_iio_custom_H_
#define SRC_LIBS_ad936x_iio_custom_H_
#include "concurrent_queue.h"
#include "gnss_time.h"
#include "pps_samplestamp.h"
#include <boost/atomic.hpp>
#include <memory>
#include <string>
#ifdef __APPLE__
#include <iio/iio.h>
#else
#include <iio.h>
#endif
#include "ad936x_iio_samples.h"
#include <ad9361.h> //multichip sync and high level functions
#include <thread>
#include <vector>
class ad936x_iio_custom
{
public:
ad936x_iio_custom(int debug_level_, int log_level_);
virtual ~ad936x_iio_custom();
bool initialize_device(std::string pluto_device_uri, std::string board_type);
bool init_config_ad9361_rx(long long bandwidth_,
long long sample_rate_,
long long freq_,
std::string rf_port_select_,
std::string rf_filter,
std::string gain_mode_rx0_,
std::string gain_mode_rx1_,
double rf_gain_rx0_,
double rf_gain_rx1_,
bool enable_ch0,
bool enable_ch1,
long long freq_2ch);
bool calibrate(int ch, double bw_hz);
double get_rx_gain(int ch_num);
bool setRXGain(int ch_num, std::string gain_mode, double gain_dB);
bool set_antenna_port(int ch, int antenna_idx);
double get_frequency(int ch);
bool set_frequency(int ch, double freq_hz);
bool start_sample_rx(bool ppsmode);
void stop_record();
void set_gnsstime_queue(std::shared_ptr<Concurrent_Queue<GnssTime>> queue);
void set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue);
bool get_rx_frequency(long long &freq_hz);
bool set_rx_frequency(long long freq_hz);
bool read_die_temp(double &temp_c);
void pop_sample_buffer(std::shared_ptr<ad936x_iio_samples> &current_buffer);
void push_sample_buffer(std::shared_ptr<ad936x_iio_samples> &current_buffer);
int n_channels;
private:
std::shared_ptr<Concurrent_Queue<GnssTime>> GnssTime_queue;
std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> Pps_queue;
bool check_device();
bool get_iio_param(iio_device *dev, const std::string &param, std::string &value);
void configure_params(struct iio_device *phy,
const std::vector<std::string> &params);
void set_params_rx(struct iio_device *phy_device,
unsigned long long frequency,
unsigned long samplerate, unsigned long bandwidth,
bool quadrature, bool rfdc, bool bbdc,
std::string gain1, double gain1_value,
std::string gain2, double gain2_value,
std::string port_select);
bool config_ad9361_dds(uint64_t freq_rf_tx_hz_,
double tx_attenuation_db_,
int64_t freq_dds_tx_hz_,
double scale_dds_,
double phase_dds_deg_);
void get_PPS_timestamp();
void capture(const std::vector<std::string> &channels);
bool select_rf_filter(std::string rf_filter);
void monitor_thread_fn();
void PlutoTxEnable(bool txon);
void setPlutoGpo(int p);
//Device structure
struct iio_context *ctx;
struct iio_device *phy;
struct iio_device *stream_dev;
struct iio_device *dds_dev;
//stream
uint64_t sample_rate_sps;
int debug_level;
int log_level;
bool PPS_mode;
std::mutex mtx;
std::condition_variable cv;
boost::atomic<bool> receive_samples;
boost::atomic<bool> fpga_overflow;
//using queues of smart pointers to preallocated buffers
Concurrent_Queue<std::shared_ptr<ad936x_iio_samples>> free_buffers;
Concurrent_Queue<std::shared_ptr<ad936x_iio_samples>> used_buffers;
std::thread capture_samples_thread;
std::thread overflow_monitor_thread;
std::thread capture_time_thread;
};
#endif /* SRC_LIBS_ad936x_iio_custom_H_ */

View File

@ -0,0 +1,26 @@
/*!
* \file ad936x_iio_samples.cc
* \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ad936x_iio_samples.h"
ad936x_iio_samples::ad936x_iio_samples()
{
for (int n = 0; n < IIO_MAX_CH; n++)
{
n_bytes[n] = 0;
n_samples[n] = 0;
}
}

View File

@ -0,0 +1,41 @@
/*!
* \file ad936x_iio_samples.h
* \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends.
* \author Javier Arribas, jarribas(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef SRC_LIBS_ad936x_iio_samples_H_
#define SRC_LIBS_ad936x_iio_samples_H_
#define IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES 32768 * 2
#define IIO_INPUTRAMFIFOSIZE 512
#define IIO_MAX_CH 4
#define IIO_MAX_BYTES_PER_CHANNEL IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2 * 2 //(2-bytes per I + 2-bytes per Q)
#include <memory>
#include <stdint.h>
#include <vector>
class ad936x_iio_samples
{
public:
ad936x_iio_samples();
uint32_t n_bytes[IIO_MAX_CH];
uint32_t n_samples[IIO_MAX_CH];
int16_t buffer[IIO_MAX_CH][IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 2]; //16 bits I,Q samples buffers
};
#endif

View File

@ -0,0 +1,20 @@
/* -------------------------------------------------------------------------
*
* Copyright (C) 2022 (see AUTHORS file for a list of contributors)
*
*
*/
#ifndef IIOPPS_PPS_SAMPLESTAMP_H
#define IIOPPS_PPS_SAMPLESTAMP_H
#include <cstdint>
class PpsSamplestamp
{
public:
uint64_t samplestamp; //PPS rising edge samples counter from the beginning of rx stream opperation. Notice that it is reseted to zero if sample buffer overflow is detected on the FPGA side
uint32_t overflow_reg; // >0 indicates overflow situation in the FPGA RX buffer
};
#endif

View File

@ -0,0 +1,154 @@
/*
* ppstcprx.cc
*
* Created on: 28 feb 2022
* Author: javier
*/
#include "ppstcprx.h"
#include <cstring>
#include <iostream>
#include <sstream>
#include <vector>
pps_tcp_rx::pps_tcp_rx()
{
// TODO Auto-generated constructor stub
is_connected = false;
clientSd = -1;
}
pps_tcp_rx::~pps_tcp_rx()
{
// TODO Auto-generated destructor stub
}
void pps_tcp_rx::set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue)
{
Pps_queue = std::move(queue);
}
bool pps_tcp_rx::send_cmd(std::string cmd)
{
if (is_connected == true)
{
// send call sends the data you specify as second param and it's length as 3rd param, also returns how many bytes were actually sent
auto bytes_sent = send(clientSd, cmd.data(), cmd.length(), 0);
if (bytes_sent <= 0)
{
std::cerr << "Connection terminated...\n";
return false;
}
else
{
std::cout << "sent bytes..\n";
}
}
else
{
return false;
}
return true;
}
void pps_tcp_rx::receive_pps(std::string ip_address, int port)
{
//create a message buffer
char buf[1500];
//setup a socket and connection tools
sockaddr_in sendSockAddr;
sendSockAddr.sin_family = AF_INET;
sendSockAddr.sin_addr.s_addr =
inet_addr(ip_address.c_str());
sendSockAddr.sin_port = htons(port);
clientSd = socket(AF_INET, SOCK_STREAM, 0);
//try to connect...
int status = connect(clientSd,
(sockaddr *)&sendSockAddr, sizeof(sendSockAddr));
if (status < 0)
{
std::cout << "pps_tcp_rx: Error connecting to PPS TCP server IP " << ip_address << " at port " << port << std::endl;
return;
}
std::string new_pps_line;
is_connected = true;
while (true)
{
int numBytesRead = recv(clientSd, buf, sizeof(buf), 0);
if (numBytesRead > 0)
{
for (int i = 0; i < numBytesRead; i++)
{
char c = buf[i];
if (c == '\n')
{
if (new_pps_line.length() > 0)
{
//std::cout << "pps_tcp_rx debug: " << new_pps_line << "\n";
//parse string and push PPS data to the PPS queue
std::stringstream ss(new_pps_line);
std::vector<std::string> data;
while (ss.good())
{
std::string substr;
std::getline(ss, substr, ',');
data.push_back(substr);
}
if (data.size() >= 2)
{
PpsSamplestamp new_pps;
//sample counter
std::size_t found = data.at(0).find("sc=");
if (found != std::string::npos)
{
try
{
new_pps.samplestamp = std::strtoul(data.at(0).substr(found + 3).c_str(), NULL, 0);
}
catch (const std::exception &ex)
{
std::cout << "pps_tcp_rx debug: sc parse error str " << data.at(0) << "\n";
}
}
else
{
std::cout << "pps_tcp_rx debug: sc parse error str " << data.at(0) << "\n";
}
found = data.at(1).find("o=");
if (found != std::string::npos)
{
try
{
new_pps.overflow_reg = std::stoi(data.at(1).substr(found + 2).c_str(), NULL, 0);
}
catch (const std::exception &ex)
{
std::cout << "pps_tcp_rx debug: o parse error str " << data.at(0) << "\n";
}
}
else
{
std::cout << "pps_tcp_rx debug: o parse error str " << data.at(1) << "\n";
}
Pps_queue->push(new_pps);
//std::cout << "pps_tcp_rx debug: pps pushed!\n";
}
else
{
std::cout << "pps_tcp_rx debug: protocol error!\n";
}
new_pps_line = "";
}
}
else
new_pps_line += c;
}
}
else
{
std::cout << "pps_tcp_rx: Socket disconnected!\n!";
break;
}
}
is_connected = false;
}

View File

@ -0,0 +1,34 @@
/*
* ppstcprx.h
*
* Created on: 28 feb 2022
* Author: javier
*/
#ifndef SRC_LIBS_PPSTCPRX_H_
#define SRC_LIBS_PPSTCPRX_H_
#include "concurrent_queue.h"
#include "pps_samplestamp.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
class pps_tcp_rx
{
private:
std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> Pps_queue;
int clientSd;
public:
volatile bool is_connected;
pps_tcp_rx();
virtual ~pps_tcp_rx();
void receive_pps(std::string ip_address, int port);
bool send_cmd(std::string cmd);
void set_pps_samplestamp_queue(std::shared_ptr<Concurrent_Queue<PpsSamplestamp>> queue);
};
#endif /* SRC_LIBS_PPSTCPRX_H_ */

View File

@ -55,6 +55,18 @@ public:
return the_queue.empty();
}
size_t size() const
{
std::unique_lock<std::mutex> lock(the_mutex);
return the_queue.size();
}
void clear()
{
std::unique_lock<std::mutex> lock(the_mutex);
the_queue = std::queue<Data>();
}
bool try_pop(Data& popped_value)
{
std::unique_lock<std::mutex> lock(the_mutex);

View File

@ -153,6 +153,7 @@
#endif
#if PLUTOSDR_DRIVER
#include "ad936x_custom_signal_source.h"
#include "plutosdr_signal_source.h"
#endif
@ -775,6 +776,12 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
out_streams, queue);
block = std::move(block_);
}
else if (implementation == "Ad936x_Custom_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<Ad936xCustomSignalSource>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
#endif
#if FMCOMMS2_DRIVER