1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-11-08 19:23:07 +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:
Lenhart
2021-04-17 14:46:48 +02:00
parent 765d547e3b
commit 4f66603464
8 changed files with 438 additions and 0 deletions

View File

@@ -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

View 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;
}

View 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_ */