1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-11-11 04:20:03 +00:00

Added ION GNSS SDR Metadata Standard signal source

This commit is contained in:
Victor Castillo 2024-06-24 04:17:40 +02:00
parent dbd94e005d
commit 1f3047c67a
No known key found for this signature in database
GPG Key ID: 8EF1FC8B7182F608
8 changed files with 855 additions and 0 deletions

View File

@ -57,6 +57,8 @@ option(ENABLE_ARRAY "Enable the use of CTTC's antenna array front-end as signal
option(ENABLE_ZMQ "Enable GNU Radio ZeroMQ Messaging, requires gr-zeromq" ON) option(ENABLE_ZMQ "Enable GNU Radio ZeroMQ Messaging, requires gr-zeromq" ON)
option(ENABLE_ION "Enable ION GNSS-SDR Metadata Standard signal source" ON)
# Performance analysis tools # Performance analysis tools
option(ENABLE_GPERFTOOLS "Enable linking to Gperftools libraries (tcmalloc and profiler)" OFF) option(ENABLE_GPERFTOOLS "Enable linking to Gperftools libraries (tcmalloc and profiler)" OFF)
@ -1422,6 +1424,19 @@ else()
endif() endif()
################################################################################
# ION GNSS-SDR Metadata Standard
################################################################################
include(FetchContent)
FetchContent_Declare(
gnss_metadata_standard
GIT_REPOSITORY https://github.com/IonMetadataWorkingGroup/GNSS-Metadata-Standard
GIT_TAG master
SOURCE_DIR ${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard
CMAKE_ARGS -DABSL_PROPAGATE_CXX_STD=ON -ABSL_BUILD_TESTING=OFF -DCMAKE_INSTALL_PREFIX=${GNSSSDR_BINARY_DIR}/gnss-metadata-standard ${ABSEIL_TOOLCHAIN_FILE}
BINARY_DIR ${GNSSSDR_BINARY_DIR}/gnss-metadata-standard
)
FetchContent_MakeAvailable(gnss_metadata_standard)
################################################################################ ################################################################################
# Abseil C++ - https://abseil.io/docs/cpp/ # Abseil C++ - https://abseil.io/docs/cpp/

View File

@ -119,6 +119,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES
two_bit_packed_file_signal_source.cc two_bit_packed_file_signal_source.cc
four_bit_cpx_file_signal_source.cc four_bit_cpx_file_signal_source.cc
file_timestamp_signal_source.cc file_timestamp_signal_source.cc
ion_gnss_ms_signal_source.cc
${OPT_DRIVER_SOURCES} ${OPT_DRIVER_SOURCES}
) )
@ -138,6 +139,7 @@ set(SIGNAL_SOURCE_ADAPTER_HEADERS
two_bit_packed_file_signal_source.h two_bit_packed_file_signal_source.h
four_bit_cpx_file_signal_source.h four_bit_cpx_file_signal_source.h
file_timestamp_signal_source.h file_timestamp_signal_source.h
ion_gnss_ms_signal_source.h
${OPT_DRIVER_HEADERS} ${OPT_DRIVER_HEADERS}
) )

View File

@ -0,0 +1,119 @@
/*!
* \file file_timestamp_signal_source.cc
* \brief This class reads samples stored in a file and generate stream tags
* with its timestamp information stored in separated file
* \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-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ion_gnss_ms_signal_source.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include <gnuradio/blocks/copy.h>
#include <string>
#include <unordered_set>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
std::vector<std::string> parse_comma_list(const std::string& str)
{
std::vector<std::string> list{};
std::size_t prev_comma_at{0};
while (prev_comma_at < str.size())
{
std::size_t comma_at = str.find_first_of(',', prev_comma_at);
if (comma_at == std::string::npos)
{
comma_at = str.size();
}
list.emplace_back(str.substr(prev_comma_at, (comma_at - prev_comma_at)));
prev_comma_at = comma_at + 1;
}
return list;
}
IONMetadataStandardSignalSource::IONMetadataStandardSignalSource(const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_streams,
unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue)
: SignalSourceBase(configuration, role, "ION_Metadata_Standard_Signal_Source"s),
metadata_file_(configuration->property(role + ".metadata_filename"s, "../data/example_capture_metadata.sdrx"s)),
stream_ids_(parse_comma_list(configuration->property(role + ".streams"s, ""s))),
metadata_(metadata_file_),
timestamp_clock_offset_ms_(configuration->property(role + ".timestamp_clock_offset_ms"s, 0.0))
{
if (in_streams > 0)
{
LOG(ERROR) << "A signal source does not have an input stream";
}
sources_ = metadata_.make_stream_sources(stream_ids_);
for (const auto& source : sources_)
{
for (int i = 0; i < source->output_stream_count(); ++i)
{
copy_blocks_.push_back(gr::blocks::copy::make(source->output_stream_item_size(i)));
}
}
}
void IONMetadataStandardSignalSource::connect(gr::top_block_sptr top_block)
{
std::size_t cumulative_index = 0;
for (const auto& source : sources_)
{
for (int i = 0; i < source->output_stream_count(); ++i, ++cumulative_index)
{
top_block->connect(source, i, copy_blocks_[cumulative_index], 0);
}
}
}
void IONMetadataStandardSignalSource::disconnect(gr::top_block_sptr top_block)
{
std::size_t cumulative_index = 0;
for (const auto& source : sources_)
{
for (int i = 0; i < source->output_stream_count(); ++i, ++cumulative_index)
{
top_block->disconnect(source, i, copy_blocks_[cumulative_index], 0);
}
}
}
gr::basic_block_sptr IONMetadataStandardSignalSource::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
// return gr_basic_block_sptr();
return IONMetadataStdFileSource::sptr();
}
gr::basic_block_sptr IONMetadataStandardSignalSource::get_right_block()
{
return get_right_block(0);
}
gr::basic_block_sptr IONMetadataStandardSignalSource::get_right_block(int RF_channel)
{
return copy_blocks_[RF_channel];
}

View File

@ -0,0 +1,78 @@
/*!
* \file file_timestamp_signal_source.h
* \brief This class reads samples stored in a file and generate stream tags
* with its timestamp information stored in separated file
* \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-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_ION_METADATA_STANDARD_SIGNAL_SOURCE_H
#define GNSS_SDR_ION_METADATA_STANDARD_SIGNAL_SOURCE_H
#include "configuration_interface.h"
#include "file_source_base.h"
#include "gnss_sdr_timestamp.h"
#include "ion_gnss_sdr_metadata_standard.h"
#include <string>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
/*!
* \brief Class that reads signals samples from a file
* and adapts it to a SignalSourceInterface
*/
class IONMetadataStandardSignalSource : public SignalSourceBase
{
public:
IONMetadataStandardSignalSource(const ConfigurationInterface* configuration, const std::string& role,
unsigned int in_streams, unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue);
~IONMetadataStandardSignalSource() override = default;
protected:
// std::tuple<size_t, bool> itemTypeToSize() override;
// double packetsPerSample() const override;
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;
inline size_t item_size() override
{
return (*sources_.begin())->output_stream_item_size(0);
}
private:
std::string metadata_file_;
std::vector<std::string> stream_ids_;
std::vector<IONMetadataStdFileSource::sptr> sources_;
std::vector<gnss_shared_ptr<gr::block>> copy_blocks_;
GnssMetadataHandler metadata_;
gnss_shared_ptr<Gnss_Sdr_Timestamp> timestamp_block_;
std::string timestamp_file_;
double timestamp_clock_offset_ms_;
uint32_t in_streams_;
uint32_t out_streams_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_ION_METADATA_STANDARD_SIGNAL_SOURCE_H

View File

@ -7,6 +7,7 @@
set(OPT_SIGNAL_SOURCE_LIB_SOURCES "") set(OPT_SIGNAL_SOURCE_LIB_SOURCES "")
set(OPT_SIGNAL_SOURCE_LIB_HEADERS "") set(OPT_SIGNAL_SOURCE_LIB_HEADERS "")
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad9361_manager.h) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad9361_manager.h)
@ -44,6 +45,11 @@ if(ENABLE_PLUTOSDR)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ppstcprx.h) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ppstcprx.h)
endif() endif()
if(ENABLE_ION)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ion_gnss_sdr_metadata_standard.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gnss_sdr_metadata_standard.h)
endif()
set(SIGNAL_SOURCE_LIB_SOURCES set(SIGNAL_SOURCE_LIB_SOURCES
rtl_tcp_commands.cc rtl_tcp_commands.cc
@ -139,6 +145,11 @@ if(ENABLE_CLANG_TIDY)
endif() endif()
endif() endif()
if(ENABLE_ION)
target_include_directories(signal_source_libs PUBLIC ${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard/source/api/inc)
target_link_libraries(signal_source_libs PUBLIC api xml)
endif()
set_property(TARGET signal_source_libs APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES set_property(TARGET signal_source_libs APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
) )

View File

@ -0,0 +1,304 @@
//
// Created by castle on 6/24/24.
//
#include "ion_gnss_sdr_metadata_standard.h"
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
GnssMetadataHandler::GnssMetadataHandler(const std::string& metadata_filepath)
: metadata_filepath_(metadata_filepath)
{
load_metadata();
}
const std::string& GnssMetadataHandler::metadata_filepath() const
{
return metadata_filepath_;
}
void GnssMetadataHandler::load_metadata()
{
try
{
GnssMetadata::XmlProcessor xml_proc;
if (!xml_proc.Load(metadata_filepath_.c_str(), false, metadata_))
{
LOG(ERROR) << "Could not load XML metadata file:";
}
}
catch (GnssMetadata::ApiException& e)
{
LOG(ERROR) << "API Exception while loadind XML metadata file: " << e.what();
}
catch (std::exception& e)
{
LOG(ERROR) << "Exception while loading XML metadata file: " << e.what();
}
}
std::vector<IONMetadataStdFileSource::sptr> GnssMetadataHandler::make_stream_sources(const std::vector<std::string>& stream_ids) const
{
std::vector<IONMetadataStdFileSource::sptr> sources{};
for (const auto& file : metadata_.Files())
{
for (const auto& block : file.Lane().Blocks())
{
for (const auto& chunk : block.Chunks())
{
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
if (std::ranges::any_of(stream_ids.begin(), stream_ids.end(), [&](const std::string& it) {
return stream.Id() == it;
}))
{
auto source = gnss_make_shared<IONMetadataStdFileSource>(
file,
block,
stream_ids);
sources.push_back(source);
// This file source will take care of any other matching streams in this block
// We can skip the rest of this block
goto next_block;
}
}
}
}
next_block:
}
}
return sources;
}
IONMetadataStdFileSource::IONMetadataStdFileSource(
const GnssMetadata::File& file,
const GnssMetadata::Block& block,
const std::vector<std::string>& stream_ids)
: gr::sync_block(
"ion_metadata_standard_source",
gr::io_signature::make(0, 0, 0),
make_output_signature(block)),
file_metadata_(file),
block_metadata_(block)
{
fd_ = std::fopen(file.Url().Value().c_str(), "rb");
std::size_t block_offset = file.Offset();
std::fseek(fd_, file.Offset() + block_offset + block.SizeHeader(), SEEK_SET);
std::size_t output_stream_offset = 0;
for (const auto& chunk : block.Chunks())
{
chunk_data_.emplace_back(std::make_shared<chunk_data_t>(chunk, stream_ids, output_stream_offset));
const std::size_t out_count = chunk_data_.back()->output_stream_count();
output_stream_offset += out_count;
for (std::size_t i = 0; i < out_count; ++i)
{
output_stream_item_sizes_.push_back(chunk_data_.back()->output_stream_item_size(i));
}
}
output_stream_count_ = output_stream_offset;
}
IONMetadataStdFileSource::~IONMetadataStdFileSource()
{
std::fclose(fd_);
}
int IONMetadataStdFileSource::work(
int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items)
{
for (int i = 0; i < noutput_items; ++i)
{
read_chunk_pattern(output_items);
}
return WORK_CALLED_PRODUCE;
}
std::size_t IONMetadataStdFileSource::output_stream_count() const
{
return output_stream_count_;
}
std::size_t IONMetadataStdFileSource::output_stream_item_size(std::size_t stream_index) const
{
return output_stream_item_sizes_[stream_index];
}
void IONMetadataStdFileSource::read_chunk_pattern(gr_vector_void_star& output_items)
{
gr_vector_void_star chunk_outputs = output_items;
for (auto& c : chunk_data_)
{
c->read_from_file(fd_);
c->write_to_output(output_items, [this](int output, int nitems) {
produce(output, nitems);
});
}
}
gr::io_signature::sptr IONMetadataStdFileSource::make_output_signature(const GnssMetadata::Block& block)
{
int nstreams = 0;
std::vector<size_t> item_sizes{};
for (const auto& chunk : block.Chunks())
{
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
++nstreams;
item_sizes.emplace_back(stream.RateFactor() * stream.Quantization());
}
}
}
return gr::io_signature::make(
nstreams,
nstreams,
item_sizes);
}
chunk_data_t::chunk_data_t(const GnssMetadata::Chunk& chunk, const std::vector<std::string>& stream_ids, std::size_t output_stream_offset)
: chunk_(chunk),
sizeword_(chunk_.SizeWord()),
countwords_(chunk_.CountWords())
{
switch (sizeword_)
{
case 1:
buffer_ = new uint8_t[countwords_];
break;
case 2:
buffer_ = new uint16_t[countwords_];
break;
case 4:
buffer_ = new uint32_t[countwords_];
break;
case 8:
buffer_ = new uint64_t[countwords_];
break;
default:
LOG(ERROR) << "Unknown word size: " << std::to_string(sizeword_);
break;
}
const std::size_t total_bitsize = sizeword_ * countwords_ * 8;
std::size_t used_bitsize = 0;
std::size_t output_streams = 0;
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
used_bitsize += stream.Packedbits();
if (std::ranges::any_of(stream_ids.begin(), stream_ids.end(), [&](const std::string& it) {
return stream.Id() == it;
}))
{
streams_.emplace_back(lump, stream, output_streams + output_stream_offset);
++output_streams;
std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor();
if (sample_bitsize <= 8)
{
output_stream_item_size_.push_back(1);
}
else if (sample_bitsize <= 16)
{
output_stream_item_size_.push_back(2);
}
else if (sample_bitsize <= 32)
{
output_stream_item_size_.push_back(4);
}
else if (sample_bitsize <= 64)
{
output_stream_item_size_.push_back(8);
}
else
{
// This shouldn't happen
output_stream_item_size_.push_back(1);
}
}
else
{
streams_.emplace_back(lump, stream, -1);
}
}
}
output_stream_count_ = output_streams;
padding_bitsize_ = total_bitsize - used_bitsize;
}
chunk_data_t::~chunk_data_t()
{
switch (sizeword_)
{
case 1:
delete[] static_cast<uint8_t*>(buffer_);
break;
case 2:
delete[] static_cast<uint16_t*>(buffer_);
break;
case 4:
delete[] static_cast<uint32_t*>(buffer_);
break;
case 8:
delete[] static_cast<uint64_t*>(buffer_);
break;
default:
break;
}
}
void chunk_data_t::read_from_file(FILE* fd)
{
std::fread(buffer_, sizeword_, countwords_, fd);
}
void chunk_data_t::write_to_output(gr_vector_void_star& outputs, const std::function<void(int output, int nitems)>& produce)
{
switch (sizeword_)
{
case 1:
unpack_words<uint8_t>(outputs, produce);
break;
case 2:
unpack_words<uint16_t>(outputs, produce);
break;
case 4:
unpack_words<uint32_t>(outputs, produce);
break;
case 8:
unpack_words<uint64_t>(outputs, produce);
break;
default:
break;
}
}
std::size_t chunk_data_t::output_stream_count() const
{
return output_stream_count_;
}
std::size_t chunk_data_t::output_stream_item_size(std::size_t stream_index) const
{
return output_stream_item_size_[stream_index];
}

View File

@ -0,0 +1,319 @@
//
// Created by castle on 6/24/24.
//
#ifndef GNSS_SDR_ION_GNSS_SDR_METADATA_STANDARD_H
#define GNSS_SDR_ION_GNSS_SDR_METADATA_STANDARD_H
#include "GnssMetadata.h"
#include "gnss_block_interface.h"
#include <gnuradio/sync_block.h>
#include <string>
class chunk_data_t
{
public:
chunk_data_t(const GnssMetadata::Chunk& chunk, const std::vector<std::string>& stream_ids, std::size_t output_stream_offset);
~chunk_data_t();
chunk_data_t(const chunk_data_t& rhl) = delete;
chunk_data_t& operator=(const chunk_data_t& rhl) = delete;
chunk_data_t(chunk_data_t&& rhl) = delete;
chunk_data_t& operator=(chunk_data_t&& rhl) = delete;
void read_from_file(FILE* fd);
void write_to_output(gr_vector_void_star& outputs, const std::function<void(int output, int nitems)>& produce);
std::size_t output_stream_count() const;
std::size_t output_stream_item_size(std::size_t stream_index) const;
private:
template <typename WT>
struct unpacking_context_t
{
WT* iterator_;
WT current_word_;
uint8_t bitshift_ = 0;
};
template <typename WT>
void unpack_words(gr_vector_void_star& outputs, const std::function<void(int output, int nitems)>& produce)
{
WT* data = static_cast<WT*>(buffer_);
// TODO - Swap endiannes if needed
unpacking_context_t<WT> ctx{};
if (chunk_.Shift() == GnssMetadata::Chunk::Left)
{
ctx.iterator_ = data;
}
else if (chunk_.Shift() == GnssMetadata::Chunk::Right)
{
ctx.iterator_ = &data[countwords_];
}
advance_word(ctx); // Initializes ctx.current_word_
// Head padding
if (padding_bitsize_ > 0 && chunk_.Padding() == GnssMetadata::Chunk::Head)
{
shift_padding(ctx, padding_bitsize_);
}
// Samples
for (const auto& [lump, stream, output_index] : streams_)
{
if (output_index == -1)
{
skip_stream(ctx, lump, stream);
}
else
{
produce(output_index, write_stream_samples(ctx, lump, stream, outputs[output_index]));
}
}
}
template <typename WT>
void skip_stream(
unpacking_context_t<WT>& ctx,
const GnssMetadata::Lump& lump,
const GnssMetadata::IonStream& stream)
{
shift_padding(ctx, stream.Packedbits());
}
template <typename WT>
std::size_t write_stream_samples(
unpacking_context_t<WT>& ctx,
const GnssMetadata::Lump& lump,
const GnssMetadata::IonStream& stream,
void*& out)
{
std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor();
std::size_t sample_count = stream.RateFactor();
if (sample_bitsize <= 8)
{
write_n_samples<WT, uint8_t>(ctx, lump.Shift(), sample_bitsize, sample_count, out);
}
else if (sample_bitsize <= 16)
{
write_n_samples<WT, uint16_t>(ctx, lump.Shift(), sample_bitsize, sample_count, out);
}
else if (sample_bitsize <= 32)
{
write_n_samples<WT, uint32_t>(ctx, lump.Shift(), sample_bitsize, sample_count, out);
}
else if (sample_bitsize <= 64)
{
write_n_samples<WT, uint64_t>(ctx, lump.Shift(), sample_bitsize, sample_count, out);
}
return sample_count;
}
template <typename WT, typename OT>
void write_n_samples(
unpacking_context_t<WT>& ctx,
GnssMetadata::Lump::LumpShift lump_shift,
uint8_t sample_bitsize,
std::size_t sample_count,
void*& out)
{
if (lump_shift == GnssMetadata::Lump::shiftLeft)
{
auto* sample = static_cast<OT*>(out);
for (int i = 0; i < sample_count; ++i)
{
shift_sample(ctx, sample_bitsize, sample);
++sample;
}
}
else if (lump_shift == GnssMetadata::Lump::shiftRight)
{
auto* sample = static_cast<OT*>(out);
sample += sample_count;
for (int i = 0; i < sample_count; ++i)
{
shift_sample(ctx, sample_bitsize, sample);
--sample;
}
}
}
template <typename WT, typename OT>
void shift_sample(unpacking_context_t<WT>& ctx, uint8_t sample_bitsize, OT* output, uint8_t output_bit_offset = 0)
{
const uint8_t word_bitsize = sizeword_ * 8;
if ((sample_bitsize + (ctx.bitshift_ % word_bitsize)) > word_bitsize)
{
uint8_t bits_shifted = word_bitsize - (ctx.bitshift_ % word_bitsize);
if (chunk_.Shift() == GnssMetadata::Chunk::Left)
{
WT mask = ~((1 << (word_bitsize - bits_shifted)) - 1);
*output |= ((ctx.current_word_ & mask) >> output_bit_offset);
ctx.current_word_ <<= bits_shifted;
}
else if (chunk_.Shift() == GnssMetadata::Chunk::Right)
{
WT mask = ((1 << (bits_shifted)) - 1);
*output |= (ctx.current_word_ & mask) << output_bit_offset;
// TODO - reverse bit order of sample? maybe?
ctx.current_word_ >>= bits_shifted;
}
advance_word(ctx);
ctx.bitshift_ += bits_shifted;
shift_sample(ctx, sample_bitsize - bits_shifted, output, bits_shifted);
}
else
{
if (chunk_.Shift() == GnssMetadata::Chunk::Left)
{
WT mask = ~((1 << (word_bitsize - sample_bitsize)) - 1);
*output |= (ctx.current_word_ & mask) >> output_bit_offset;
ctx.current_word_ <<= sample_bitsize;
}
else if (chunk_.Shift() == GnssMetadata::Chunk::Right)
{
WT mask = ((1 << (sample_bitsize)) - 1);
*output |= (ctx.current_word_ & mask) << output_bit_offset;
// TODO - reverse bit order of sample? maybe?
ctx.current_word_ >>= sample_bitsize;
}
ctx.bitshift_ += sample_bitsize;
}
}
template <typename WT>
void shift_padding(unpacking_context_t<WT>& ctx, uint8_t n_bits)
{
const uint8_t word_bitsize = sizeword_ * 8;
if ((n_bits + (ctx.bitshift_ % word_bitsize)) > word_bitsize)
{
uint8_t bits_shifted = word_bitsize - (ctx.bitshift_ % word_bitsize);
if (chunk_.Shift() == GnssMetadata::Chunk::Left)
{
ctx.current_word_ <<= bits_shifted;
}
else if (chunk_.Shift() == GnssMetadata::Chunk::Right)
{
ctx.current_word_ >>= bits_shifted;
}
advance_word(ctx);
ctx.bitshift_ += bits_shifted;
shift_padding(ctx, n_bits - bits_shifted);
}
else
{
if (chunk_.Shift() == GnssMetadata::Chunk::Left)
{
ctx.current_word_ <<= n_bits;
}
else if (chunk_.Shift() == GnssMetadata::Chunk::Right)
{
ctx.current_word_ >>= n_bits;
}
ctx.bitshift_ += n_bits;
}
}
template <typename WT>
void advance_word(unpacking_context_t<WT>& ctx)
{
WT word = *ctx.iterator_;
if (chunk_.Shift() == GnssMetadata::Chunk::Left)
{
++ctx.iterator_;
}
else if (chunk_.Shift() == GnssMetadata::Chunk::Right)
{
--ctx.iterator_;
}
ctx.current_word_ = word;
}
private:
const GnssMetadata::Chunk& chunk_;
uint8_t sizeword_;
uint8_t countwords_;
uint8_t padding_bitsize_;
std::size_t output_stream_count_;
std::vector<std::size_t> output_stream_item_size_;
struct stream_metadata_t
{
const GnssMetadata::Lump& lump;
const GnssMetadata::IonStream& stream;
int output_index = -1;
};
std::vector<stream_metadata_t> streams_;
void* buffer_;
};
class IONMetadataStdFileSource : public gr::sync_block
{
public:
using sptr = gnss_shared_ptr<IONMetadataStdFileSource>;
IONMetadataStdFileSource(
const GnssMetadata::File& file,
const GnssMetadata::Block& block,
const std::vector<std::string>& stream_ids);
~IONMetadataStdFileSource() override;
int work(
int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items) override;
std::size_t output_stream_count() const;
std::size_t output_stream_item_size(std::size_t stream_index) const;
private:
void read_chunk_pattern(gr_vector_void_star& output_items);
private:
static gr::io_signature::sptr make_output_signature(const GnssMetadata::Block& block);
private:
const GnssMetadata::File& file_metadata_;
const GnssMetadata::Block& block_metadata_;
FILE* fd_;
std::size_t output_stream_count_;
std::vector<std::size_t> output_stream_item_sizes_;
std::vector<std::shared_ptr<chunk_data_t>> chunk_data_;
};
class GnssMetadataHandler
{
public:
explicit GnssMetadataHandler(const std::string& metadata_filepath);
std::vector<IONMetadataStdFileSource::sptr> make_stream_sources(const std::vector<std::string>& stream_ids) const;
public: // Getters
const std::string& metadata_filepath() const;
private:
void load_metadata();
private:
std::string metadata_filepath_;
GnssMetadata::Metadata metadata_;
};
#endif // GNSS_SDR_ION_GNSS_SDR_METADATA_STANDARD_H

View File

@ -113,6 +113,7 @@
#include "tracking_interface.h" #include "tracking_interface.h"
#include "two_bit_cpx_file_signal_source.h" #include "two_bit_cpx_file_signal_source.h"
#include "two_bit_packed_file_signal_source.h" #include "two_bit_packed_file_signal_source.h"
#include "ion_gnss_ms_signal_source.h"
#include <cstdlib> // for exit #include <cstdlib> // for exit
#include <exception> // for exception #include <exception> // for exception
#include <iostream> // for cerr #include <iostream> // for cerr
@ -759,6 +760,12 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
block = std::move(block_); block = std::move(block_);
} }
#endif #endif
else if (implementation == "ION_Metadata_Standard_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<IONMetadataStandardSignalSource>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
#if RAW_ARRAY_DRIVER #if RAW_ARRAY_DRIVER
else if (implementation == "Raw_Array_Signal_Source") else if (implementation == "Raw_Array_Signal_Source")