mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-12 11:10:33 +00:00
Implemented a custom FIFO reading gnu radio block + adapter.
Reads samples from unix fifo into gnss-sdr. Use cases: - multiplex signal streams outside of gnss-sdr - another program holds access to the SDR - the SDR is not supported by gnss-sdr but can dump the signal to a fifo
This commit is contained in:
parent
765d547e3b
commit
4f66603464
47
conf/gnss-sdr_GPS_L1_fifo.conf
Normal file
47
conf/gnss-sdr_GPS_L1_fifo.conf
Normal file
@ -0,0 +1,47 @@
|
||||
[GNSS-SDR]
|
||||
|
||||
;######### GLOBAL OPTIONS ##################
|
||||
GNSS-SDR.internal_fs_sps=25000000
|
||||
|
||||
;######### SIGNAL_SOURCE CONFIG ############
|
||||
SignalSource.implementation=Fifo_Signal_Source
|
||||
SignalSource.filename=fifo.fifo ; example usage: mkfifo fifo.fifo && cat path_to.bin >> fifo.fifo
|
||||
SignalSource.sample_type=ishort; ; sample representation in fifo stream - will always output gr_complex
|
||||
SignalSource.dump=false
|
||||
;SignalSource.dump_filename=dump
|
||||
|
||||
;######### SIGNAL_CONDITIONER CONFIG ############
|
||||
SignalConditioner.implementation=Pass_Through
|
||||
|
||||
;######### CHANNELS GLOBAL CONFIG ############
|
||||
Channels_1C.count=8
|
||||
Channels.in_acquisition=1
|
||||
Channel.signal=1C
|
||||
|
||||
;######### ACQUISITION GLOBAL CONFIG ############
|
||||
Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition
|
||||
Acquisition_1C.item_type=gr_complex
|
||||
Acquisition_1C.pfa=0.01
|
||||
Acquisition_1C.doppler_max=10000
|
||||
Acquisition_1C.doppler_step=250
|
||||
|
||||
;######### TRACKING GLOBAL CONFIG ############
|
||||
Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking
|
||||
Tracking_1C.item_type=gr_complex
|
||||
Tracking_1C.pll_bw_hz=40.0;
|
||||
Tracking_1C.dll_bw_hz=4.0;
|
||||
|
||||
;######### TELEMETRY DECODER GPS CONFIG ############
|
||||
TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder
|
||||
|
||||
;######### OBSERVABLES CONFIG ############
|
||||
Observables.implementation=Hybrid_Observables
|
||||
|
||||
;######### PVT CONFIG ############
|
||||
PVT.implementation=RTKLIB_PVT
|
||||
PVT.positioning_mode=Single
|
||||
PVT.output_rate_ms=100
|
||||
PVT.display_rate_ms=500
|
||||
PVT.iono_model=Broadcast
|
||||
PVT.trop_model=Saastamoinen
|
||||
PVT.output_path=./files
|
@ -95,6 +95,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES
|
||||
signal_source_base.cc
|
||||
file_source_base.cc
|
||||
file_signal_source.cc
|
||||
fifo_signal_source.cc
|
||||
multichannel_file_signal_source.cc
|
||||
gen_signal_source.cc
|
||||
nsr_file_signal_source.cc
|
||||
@ -111,6 +112,7 @@ set(SIGNAL_SOURCE_ADAPTER_HEADERS
|
||||
signal_source_base.h
|
||||
file_source_base.h
|
||||
file_signal_source.h
|
||||
fifo_signal_source.h
|
||||
multichannel_file_signal_source.h
|
||||
gen_signal_source.h
|
||||
nsr_file_signal_source.h
|
||||
|
93
src/algorithms/signal_source/adapters/fifo_signal_source.cc
Normal file
93
src/algorithms/signal_source/adapters/fifo_signal_source.cc
Normal file
@ -0,0 +1,93 @@
|
||||
/*!
|
||||
* \file file_source_base.cc
|
||||
*
|
||||
* \brief Implementation of the class for retrieving samples through a Unix fifo
|
||||
* \author Malte Lenhart, 2021. malte.lenhart(at)mailbox.org
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* 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)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "fifo_signal_source.h"
|
||||
#include "configuration_interface.h"
|
||||
#include "fifo_reader.h"
|
||||
#include "gnss_sdr_filesystem.h"
|
||||
#include "gnss_sdr_flags.h"
|
||||
#include "gnss_sdr_string_literals.h"
|
||||
#include "gnss_sdr_valve.h"
|
||||
#include <glog/logging.h>
|
||||
#include <cmath> // ceil, floor
|
||||
#include <fstream>
|
||||
#include <utility> // move
|
||||
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
FifoSignalSource::FifoSignalSource(ConfigurationInterface const* configuration,
|
||||
std::string const& role, unsigned int in_streams, unsigned int out_streams,
|
||||
Concurrent_Queue<pmt::pmt_t>* queue)
|
||||
: SignalSourceBase(configuration, role, "Fifo_Signal_Source"s),
|
||||
item_size_(sizeof(gr_complex)), // currenty output item size is always gr_complex
|
||||
fifo_reader_(FifoReader::make(configuration->property(role + ".filename"s, "../data/example_capture.dat"s),
|
||||
configuration->property(role + ".sample_type"s, "ishort"s))),
|
||||
dump_(configuration->property(role + ".dump", false)),
|
||||
dump_filename_(configuration->property(role + ".dump_filename"s, "./data/signal_source.dat"s))
|
||||
{
|
||||
if (dump_)
|
||||
{
|
||||
DLOG(INFO) << "Dumping output into file " << (dump_filename_ + ".bin"s);
|
||||
file_sink_ = gr::blocks::file_sink::make(item_size_, (dump_filename_ + ".bin").c_str());
|
||||
}
|
||||
|
||||
if (in_streams > 0)
|
||||
{
|
||||
LOG(ERROR) << "A signal source does not have an input stream";
|
||||
}
|
||||
if (out_streams > 1)
|
||||
{
|
||||
LOG(ERROR) << "This implementation only supports one output stream";
|
||||
}
|
||||
}
|
||||
|
||||
void FifoSignalSource::connect(gr::top_block_sptr top_block)
|
||||
{
|
||||
// here we could add a throttle as done in the file_source_base if required
|
||||
if (dump_)
|
||||
{
|
||||
top_block->connect(fifo_reader_, 0, file_sink_, 0);
|
||||
DLOG(INFO) << "connected source to file sink";
|
||||
}
|
||||
}
|
||||
|
||||
void FifoSignalSource::disconnect(gr::top_block_sptr top_block)
|
||||
{
|
||||
if (dump_)
|
||||
{
|
||||
top_block->disconnect(fifo_reader_, 0, file_sink_, 0);
|
||||
DLOG(INFO) << "disconnected source to file sink";
|
||||
}
|
||||
}
|
||||
|
||||
size_t FifoSignalSource::item_size()
|
||||
{
|
||||
return item_size_;
|
||||
}
|
||||
|
||||
gr::basic_block_sptr FifoSignalSource::get_left_block()
|
||||
{
|
||||
LOG(WARNING) << "Left block of a signal source should not be retrieved";
|
||||
return gr::blocks::file_source::sptr();
|
||||
}
|
||||
|
||||
|
||||
gr::basic_block_sptr FifoSignalSource::get_right_block()
|
||||
{
|
||||
return fifo_reader_;
|
||||
}
|
83
src/algorithms/signal_source/adapters/fifo_signal_source.h
Normal file
83
src/algorithms/signal_source/adapters/fifo_signal_source.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*!
|
||||
* \file file_source_base.h
|
||||
*
|
||||
* \brief Header file of the class for retrieving samples through a Unix fifo
|
||||
* \author Malte Lenhart, 2021. malte.lenhart(at)mailbox.org
|
||||
*
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* 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)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_FIFO_SOURCE_BASE_H
|
||||
#define GNSS_SDR_FIFO_SOURCE_BASE_H
|
||||
|
||||
#include "concurrent_queue.h"
|
||||
#include "file_source_base.h"
|
||||
#include "gnss_block_interface.h"
|
||||
#include <gnuradio/blocks/file_source.h>
|
||||
#include <gnuradio/blocks/throttle.h>
|
||||
#include <pmt/pmt.h>
|
||||
#include <tuple>
|
||||
|
||||
// for dump
|
||||
#include <gnuradio/blocks/file_sink.h>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
|
||||
class ConfigurationInterface;
|
||||
|
||||
|
||||
//! \brief Class that reads a sample stream from a Unix fifo
|
||||
//!
|
||||
//! This class supports the following properties:
|
||||
//!
|
||||
//! .filename - the path to the input file
|
||||
//! - may be overridden by the -signal_source or -s command-line arguments
|
||||
//!
|
||||
//! .sample_type - data type read out from the fifo. default ishort ;
|
||||
//! - note: not output format. that is always gr_complex
|
||||
//!
|
||||
//! .dump - whether to archive input data
|
||||
//!
|
||||
//! .dump_filename - if dumping, path to file for output
|
||||
|
||||
|
||||
class FifoSignalSource : public SignalSourceBase
|
||||
{
|
||||
public:
|
||||
FifoSignalSource(const ConfigurationInterface* configuration, const std::string& role,
|
||||
unsigned int in_streams, unsigned int out_streams,
|
||||
Concurrent_Queue<pmt::pmt_t>* queue);
|
||||
|
||||
~FifoSignalSource() = default;
|
||||
|
||||
//! override methods from GNSSBlockInterface
|
||||
void connect(gr::top_block_sptr top_block) override;
|
||||
void disconnect(gr::top_block_sptr top_block) override;
|
||||
size_t item_size() override;
|
||||
gr::basic_block_sptr get_left_block() override;
|
||||
gr::basic_block_sptr get_right_block() override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
//! output size - always gr_complex
|
||||
const size_t item_size_;
|
||||
//! internal fifo_reader_ class acts as signal source
|
||||
const gnss_shared_ptr<gr::block> fifo_reader_;
|
||||
|
||||
gnss_shared_ptr<gr::block> file_sink_;
|
||||
const bool dump_;
|
||||
const std::string dump_filename_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -14,6 +14,7 @@ endif()
|
||||
|
||||
|
||||
set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
|
||||
fifo_reader.cc
|
||||
unpack_byte_2bit_samples.cc
|
||||
unpack_byte_2bit_cpx_samples.cc
|
||||
unpack_byte_4bit_samples.cc
|
||||
@ -27,6 +28,7 @@ set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
|
||||
|
||||
|
||||
set(SIGNAL_SOURCE_GR_BLOCKS_HEADERS
|
||||
fifo_reader.h
|
||||
unpack_byte_2bit_samples.h
|
||||
unpack_byte_2bit_cpx_samples.h
|
||||
unpack_byte_4bit_samples.h
|
||||
|
111
src/algorithms/signal_source/gnuradio_blocks/fifo_reader.cc
Normal file
111
src/algorithms/signal_source/gnuradio_blocks/fifo_reader.cc
Normal file
@ -0,0 +1,111 @@
|
||||
/*!
|
||||
* \file fifo_reader.cc
|
||||
*
|
||||
* \brief Implementation of the class to retrieve samples from an existing Unix FIFO
|
||||
* \author Malte Lenhart, 2021. malte.lenhart(at)mailbox.org
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "fifo_reader.h"
|
||||
#include <glog/logging.h>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
// initial construction; pass to private constructor
|
||||
FifoReader::sptr FifoReader::make(const std::string &file_name, const std::string &sample_type)
|
||||
{
|
||||
return gnuradio::get_initial_sptr(new FifoReader(file_name, sample_type));
|
||||
}
|
||||
|
||||
// private constructor called by ::make
|
||||
FifoReader::FifoReader(const std::string &file_name, const std::string &sample_type)
|
||||
: gr::sync_block("fifo_reader",
|
||||
gr::io_signature::make(0, 0, 0), // no input
|
||||
gr::io_signature::make(1, 1, sizeof(gr_complex))), // <+MIN_OUT+>, <+MAX_OUT+>, sizeof(<+OTYPE+>)
|
||||
file_name_(file_name),
|
||||
sample_type_(sample_type)
|
||||
{
|
||||
std::cout << "Starting FifoReader\n";
|
||||
// instream: https://en.cppreference.com/w/cpp/io/basic_ifstream
|
||||
}
|
||||
|
||||
bool FifoReader::start()
|
||||
{
|
||||
fifo_.open(file_name_, std::ios::binary);
|
||||
if (!fifo_.is_open())
|
||||
{
|
||||
DLOG(ERROR) << "Error opening fifo\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// work loop
|
||||
// taken from here: https://stackoverflow.com/questions/25546619/work-with-fifo-in-c-blocking-read
|
||||
int FifoReader::work(int noutput_items,
|
||||
__attribute__((unused)) gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
if (output_items.size() > 1)
|
||||
{
|
||||
DLOG(ERROR) << "FifoReader connected to too many outputs\n";
|
||||
}
|
||||
|
||||
// read samples out
|
||||
size_t items_retrieved = 0;
|
||||
if (sample_type_ == "ishort")
|
||||
{
|
||||
// ishort == int16_t
|
||||
items_retrieved = read_interleaved<int16_t>(noutput_items, output_items);
|
||||
}
|
||||
else if (sample_type_ == "gr_complex")
|
||||
{
|
||||
DLOG(WARNING) << sample_type_ << " is not yet tested. Please consider removing this warning if tested successfully\n";
|
||||
items_retrieved = read_gr_complex(noutput_items, output_items);
|
||||
}
|
||||
else
|
||||
{
|
||||
// please see gr_complex_ip_packet_source for inspiration on how to implement other sample types
|
||||
DLOG(ERROR) << sample_type_ << " is unfortunately not yet implemented as sample type\n";
|
||||
}
|
||||
|
||||
// we return varying number of data -> call produce & return flag
|
||||
produce(0, items_retrieved);
|
||||
return this->WORK_CALLED_PRODUCE;
|
||||
}
|
||||
|
||||
// read gr_complex items from fifo
|
||||
size_t FifoReader::read_gr_complex(int noutput_items, gr_vector_void_star &output_items)
|
||||
{
|
||||
size_t items_retrieved = 0;
|
||||
for (int n = 0; n < noutput_items; n++)
|
||||
{
|
||||
std::vector<char> buffer(4);
|
||||
fifo_.read((char *)&buffer[0], buffer.size());
|
||||
if (fifo_.good())
|
||||
{
|
||||
gr_complex sample;
|
||||
memcpy(&sample, &buffer[0], sizeof(sample));
|
||||
static_cast<gr_complex *>(output_items.at(0))[n] = sample;
|
||||
items_retrieved++;
|
||||
}
|
||||
else if (fifo_.eof() || fifo_.fail())
|
||||
{
|
||||
// not enough samples.. what if we did not have a complete sample? need to reassemble in between loops
|
||||
fifo_.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return items_retrieved;
|
||||
}
|
93
src/algorithms/signal_source/gnuradio_blocks/fifo_reader.h
Normal file
93
src/algorithms/signal_source/gnuradio_blocks/fifo_reader.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*!
|
||||
* \file fifo_reader.h
|
||||
*
|
||||
* \brief Header file to retrieve samples from an existing Unix FIFO
|
||||
* \author Malte Lenhart, 2021. malte.lenhart(at)mailbox.org
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||
* This file is part of GNSS-SDR.
|
||||
*
|
||||
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_SDR_FIFO_READER_H_
|
||||
#define GNSS_SDR_FIFO_READER_H_
|
||||
|
||||
#include "gnss_block_interface.h"
|
||||
#include <gnuradio/sync_block.h>
|
||||
#include <fstream> // std::ifstream
|
||||
|
||||
/** \addtogroup Signal_Source
|
||||
* \{ */
|
||||
/** \addtogroup Signal_Source_gnuradio_blocks
|
||||
* \{ */
|
||||
|
||||
class FifoReader : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
//! \brief static function to create a class instance
|
||||
using sptr = gnss_shared_ptr<FifoReader>;
|
||||
static sptr make(const std::string &file_name, const std::string &sample_type);
|
||||
|
||||
~FifoReader() = default;
|
||||
|
||||
//! initialize istream resource for fifo
|
||||
bool start();
|
||||
|
||||
// gnu radio work cycle function
|
||||
int work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
private:
|
||||
//! \brief Constructor
|
||||
//! private constructor called by function make
|
||||
//! (gr handles this with public and private header pair)
|
||||
FifoReader(const std::string &file_name, const std::string &sample_type);
|
||||
|
||||
|
||||
size_t read_gr_complex(int noutput_items, gr_vector_void_star &output_items);
|
||||
//! function to read data out of fifo which is stored as interleaved I/Q stream.
|
||||
//! template argument determines sample_type
|
||||
template <typename Type>
|
||||
size_t read_interleaved(int noutput_items, gr_vector_void_star &output_items)
|
||||
{
|
||||
size_t items_retrieved = 0;
|
||||
for (int n = 0; n < noutput_items; n++)
|
||||
{
|
||||
// TODO: try if performance increases if we copy larger chunks to vector.
|
||||
// read from fifo: https://en.cppreference.com/w/cpp/io/basic_ifstream
|
||||
std::vector<char> buffer(4); // dynamically change buffer size depending on read speed? where to throttle?
|
||||
fifo_.read((char *)&buffer[0], buffer.size());
|
||||
if (fifo_.good())
|
||||
{
|
||||
Type real;
|
||||
Type imag;
|
||||
memcpy(&real, &buffer[0], sizeof(real));
|
||||
memcpy(&imag, &buffer[2], sizeof(imag));
|
||||
static_cast<gr_complex *>(output_items.at(0))[n] = gr_complex(imag, real);
|
||||
items_retrieved++;
|
||||
}
|
||||
else if (fifo_.eof() || fifo_.fail())
|
||||
{
|
||||
// not enough samples.. what if we did not have a complete sample? need to reassemble in between loops
|
||||
fifo_.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return items_retrieved;
|
||||
}
|
||||
|
||||
const std::string file_name_;
|
||||
const std::string sample_type_;
|
||||
std::ifstream fifo_;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif /* GNSS_SDR_FIFO_READER_H_ */
|
@ -38,6 +38,7 @@
|
||||
#include "configuration_interface.h"
|
||||
#include "direct_resampler_conditioner.h"
|
||||
#include "file_signal_source.h"
|
||||
#include "fifo_signal_source.h"
|
||||
#include "fir_filter.h"
|
||||
#include "freq_xlating_fir_filter.h"
|
||||
#include "galileo_e1_dll_pll_veml_tracking.h"
|
||||
@ -647,6 +648,12 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
|
||||
}
|
||||
|
||||
// SIGNAL SOURCES ----------------------------------------------------------
|
||||
else if (implementation == "Fifo_Signal_Source")
|
||||
{
|
||||
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<FifoSignalSource>(configuration, role, in_streams,
|
||||
out_streams, queue);
|
||||
block = std::move(block_);
|
||||
}
|
||||
else if (implementation == "File_Signal_Source")
|
||||
{
|
||||
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<FileSignalSource>(configuration, role, in_streams,
|
||||
|
Loading…
Reference in New Issue
Block a user