From 469eaf76e5cc241e1f0c452e1a1665292c3ff6b8 Mon Sep 17 00:00:00 2001 From: Victor Castillo Date: Tue, 23 Jul 2024 01:13:34 +0200 Subject: [PATCH] Fixed decoding errors and refactored each class into its own file --- .../signal_source/adapters/CMakeLists.txt | 4 +- ...al_source.cc => ion_gsms_signal_source.cc} | 27 +- ...gnal_source.h => ion_gsms_signal_source.h} | 19 +- .../signal_source/libs/CMakeLists.txt | 8 +- .../libs/ion_gnss_sdr_metadata_standard.cc | 340 ------------ .../libs/ion_gnss_sdr_metadata_standard.h | 321 ----------- src/algorithms/signal_source/libs/ion_gsms.cc | 123 +++++ src/algorithms/signal_source/libs/ion_gsms.h | 64 +++ .../signal_source/libs/ion_gsms_chunk_data.cc | 108 ++++ .../signal_source/libs/ion_gsms_chunk_data.h | 510 ++++++++++++++++++ .../libs/ion_gsms_metadata_handler.cc | 101 ++++ .../libs/ion_gsms_metadata_handler.h | 47 ++ src/core/receiver/gnss_block_factory.cc | 6 +- 13 files changed, 987 insertions(+), 691 deletions(-) rename src/algorithms/signal_source/adapters/{ion_gnss_ms_signal_source.cc => ion_gsms_signal_source.cc} (78%) rename src/algorithms/signal_source/adapters/{ion_gnss_ms_signal_source.h => ion_gsms_signal_source.h} (76%) delete mode 100644 src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.cc delete mode 100644 src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.h create mode 100644 src/algorithms/signal_source/libs/ion_gsms.cc create mode 100644 src/algorithms/signal_source/libs/ion_gsms.h create mode 100644 src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc create mode 100644 src/algorithms/signal_source/libs/ion_gsms_chunk_data.h create mode 100644 src/algorithms/signal_source/libs/ion_gsms_metadata_handler.cc create mode 100644 src/algorithms/signal_source/libs/ion_gsms_metadata_handler.h diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index 54d577c53..9ff0ab434 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -119,7 +119,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES two_bit_packed_file_signal_source.cc four_bit_cpx_file_signal_source.cc file_timestamp_signal_source.cc - ion_gnss_ms_signal_source.cc + ion_gsms_signal_source.cc ${OPT_DRIVER_SOURCES} ) @@ -139,7 +139,7 @@ set(SIGNAL_SOURCE_ADAPTER_HEADERS two_bit_packed_file_signal_source.h four_bit_cpx_file_signal_source.h file_timestamp_signal_source.h - ion_gnss_ms_signal_source.h + ion_gsms_signal_source.h ${OPT_DRIVER_HEADERS} ) diff --git a/src/algorithms/signal_source/adapters/ion_gnss_ms_signal_source.cc b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.cc similarity index 78% rename from src/algorithms/signal_source/adapters/ion_gnss_ms_signal_source.cc rename to src/algorithms/signal_source/adapters/ion_gsms_signal_source.cc index fe81e4556..e4becf5e3 100644 --- a/src/algorithms/signal_source/adapters/ion_gnss_ms_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.cc @@ -1,8 +1,7 @@ /*! - * \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 + * \file ion_gsms_signal_source.h + * \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com * * ----------------------------------------------------------------------------- * @@ -15,9 +14,9 @@ * ----------------------------------------------------------------------------- */ -#include "ion_gnss_ms_signal_source.h" #include "gnss_sdr_flags.h" #include "gnss_sdr_string_literals.h" +#include "ion_gsms_signal_source.h" #include #include #include @@ -49,7 +48,7 @@ std::vector parse_comma_list(const std::string& str) return list; } -IONMetadataStandardSignalSource::IONMetadataStandardSignalSource(const ConfigurationInterface* configuration, +IONGSMSSignalSource::IONGSMSSignalSource(const ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, @@ -58,7 +57,9 @@ IONMetadataStandardSignalSource::IONMetadataStandardSignalSource(const Configura 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)) + timestamp_clock_offset_ms_(configuration->property(role + ".timestamp_clock_offset_ms"s, 0.0)), + in_streams_(in_streams), + out_streams_(out_streams) { if (in_streams > 0) { @@ -77,7 +78,7 @@ IONMetadataStandardSignalSource::IONMetadataStandardSignalSource(const Configura } -void IONMetadataStandardSignalSource::connect(gr::top_block_sptr top_block) +void IONGSMSSignalSource::connect(gr::top_block_sptr top_block) { std::size_t cumulative_index = 0; for (const auto& source : sources_) @@ -89,7 +90,7 @@ void IONMetadataStandardSignalSource::connect(gr::top_block_sptr top_block) } } -void IONMetadataStandardSignalSource::disconnect(gr::top_block_sptr top_block) +void IONGSMSSignalSource::disconnect(gr::top_block_sptr top_block) { std::size_t cumulative_index = 0; for (const auto& source : sources_) @@ -101,19 +102,19 @@ void IONMetadataStandardSignalSource::disconnect(gr::top_block_sptr top_block) } } -gr::basic_block_sptr IONMetadataStandardSignalSource::get_left_block() +gr::basic_block_sptr IONGSMSSignalSource::get_left_block() { LOG(WARNING) << "Trying to get signal source left block."; // return gr_basic_block_sptr(); - return IONMetadataStdFileSource::sptr(); + return IONGSMSFileSource::sptr(); } -gr::basic_block_sptr IONMetadataStandardSignalSource::get_right_block() +gr::basic_block_sptr IONGSMSSignalSource::get_right_block() { return get_right_block(0); } -gr::basic_block_sptr IONMetadataStandardSignalSource::get_right_block(int RF_channel) +gr::basic_block_sptr IONGSMSSignalSource::get_right_block(int RF_channel) { return copy_blocks_[RF_channel]; } diff --git a/src/algorithms/signal_source/adapters/ion_gnss_ms_signal_source.h b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.h similarity index 76% rename from src/algorithms/signal_source/adapters/ion_gnss_ms_signal_source.h rename to src/algorithms/signal_source/adapters/ion_gsms_signal_source.h index ed84cab5c..9d959279f 100644 --- a/src/algorithms/signal_source/adapters/ion_gnss_ms_signal_source.h +++ b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.h @@ -1,8 +1,7 @@ /*! - * \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 + * \file ion_gsms_signal_source.h + * \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com * * ----------------------------------------------------------------------------- * @@ -22,7 +21,7 @@ #include "configuration_interface.h" #include "file_source_base.h" #include "gnss_sdr_timestamp.h" -#include "ion_gnss_sdr_metadata_standard.h" +#include "ion_gsms.h" #include /** \addtogroup Signal_Source @@ -34,14 +33,14 @@ * \brief Class that reads signals samples from a file * and adapts it to a SignalSourceInterface */ -class IONMetadataStandardSignalSource : public SignalSourceBase +class IONGSMSSignalSource : public SignalSourceBase { public: - IONMetadataStandardSignalSource(const ConfigurationInterface* configuration, const std::string& role, + IONGSMSSignalSource(const ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams, Concurrent_Queue* queue); - ~IONMetadataStandardSignalSource() override = default; + ~IONGSMSSignalSource() override = default; protected: // std::tuple itemTypeToSize() override; @@ -60,9 +59,9 @@ protected: private: std::string metadata_file_; std::vector stream_ids_; - std::vector sources_; + std::vector sources_; std::vector> copy_blocks_; - GnssMetadataHandler metadata_; + IONGSMSMetadataHandler metadata_; gnss_shared_ptr timestamp_block_; std::string timestamp_file_; diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index f0b2c09fd..fb7faf9ee 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -46,8 +46,12 @@ if(ENABLE_PLUTOSDR) 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) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ion_gsms.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms.h) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ion_gsms_chunk_data.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_chunk_data.h) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ion_gsms_metadata_handler.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_metadata_handler.h) endif() diff --git a/src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.cc b/src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.cc deleted file mode 100644 index 3c8f1809d..000000000 --- a/src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.cc +++ /dev/null @@ -1,340 +0,0 @@ -// -// Created by castle on 6/24/24. -// - -#include "ion_gnss_sdr_metadata_standard.h" - -#if USE_GLOG_AND_GFLAGS -#include -#else -#include -#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 GnssMetadataHandler::make_stream_sources(const std::vector& stream_ids) const -{ - std::vector sources{}; - for (const auto& file : metadata_.Files()) - { - for (const auto& lane : metadata_.Lanes()) - { - if (lane.Id() == file.Lane().Id()) - { - for (const auto& block : 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( - metadata_filepath_, - 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: - } - break; - } - } - } - - return sources; -} - - -IONMetadataStdFileSource::IONMetadataStdFileSource( - const std::filesystem::path& metadata_filepath, - const GnssMetadata::File& file, - const GnssMetadata::Block& block, - const std::vector& stream_ids) - : gr::sync_block( - "ion_metadata_standard_source", - gr::io_signature::make(0, 0, 0), - make_output_signature(block, stream_ids)), - file_metadata_(file), - block_metadata_(block) -{ - std::filesystem::path data_filepath = metadata_filepath.parent_path() / file.Url().Value(); - fd_ = std::fopen(data_filepath.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, 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, const std::vector& stream_ids) -{ - int nstreams = 0; - std::vector item_sizes{}; - - 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; - })) - { - ++nstreams; - std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor(); - if (sample_bitsize <= 8) - { - item_sizes.push_back(1); - } - else if (sample_bitsize <= 16) - { - item_sizes.push_back(2); - } - else if (sample_bitsize <= 32) - { - item_sizes.push_back(4); - } - else if (sample_bitsize <= 64) - { - item_sizes.push_back(8); - } - else - { - // This shouldn't happen - item_sizes.push_back(1); - } - } - } - } - } - - return gr::io_signature::make( - nstreams, - nstreams, - item_sizes); -} - - -chunk_data_t::chunk_data_t(const GnssMetadata::Chunk& chunk, const std::vector& 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(buffer_); - break; - case 2: - delete[] static_cast(buffer_); - break; - case 4: - delete[] static_cast(buffer_); - break; - case 8: - delete[] static_cast(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& produce) -{ - switch (sizeword_) - { - case 1: - unpack_words(outputs, produce); - break; - case 2: - unpack_words(outputs, produce); - break; - case 4: - unpack_words(outputs, produce); - break; - case 8: - unpack_words(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]; -} diff --git a/src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.h b/src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.h deleted file mode 100644 index 0543de71d..000000000 --- a/src/algorithms/signal_source/libs/ion_gnss_sdr_metadata_standard.h +++ /dev/null @@ -1,321 +0,0 @@ -// -// 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 -#include -#include - -class chunk_data_t -{ -public: - chunk_data_t(const GnssMetadata::Chunk& chunk, const std::vector& 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& produce); - - std::size_t output_stream_count() const; - std::size_t output_stream_item_size(std::size_t stream_index) const; - -private: - template - struct unpacking_context_t - { - WT* iterator_; - WT current_word_; - uint8_t bitshift_ = 0; - }; - - template - void unpack_words(gr_vector_void_star& outputs, const std::function& produce) - { - WT* data = static_cast(buffer_); - // TODO - Swap endiannes if needed - - unpacking_context_t 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 - void skip_stream( - unpacking_context_t& ctx, - const GnssMetadata::Lump& lump, - const GnssMetadata::IonStream& stream) - { - shift_padding(ctx, stream.Packedbits()); - } - - template - std::size_t write_stream_samples( - unpacking_context_t& 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(ctx, lump.Shift(), sample_bitsize, sample_count, out); - } - else if (sample_bitsize <= 16) - { - write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, out); - } - else if (sample_bitsize <= 32) - { - write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, out); - } - else if (sample_bitsize <= 64) - { - write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, out); - } - - return sample_count; - } - - template - void write_n_samples( - unpacking_context_t& 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(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(out); - sample += sample_count; - for (int i = 0; i < sample_count; ++i) - { - shift_sample(ctx, sample_bitsize, sample); - --sample; - } - } - } - - template - void shift_sample(unpacking_context_t& 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 - void shift_padding(unpacking_context_t& 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 - void advance_word(unpacking_context_t& 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 output_stream_item_size_; - - struct stream_metadata_t - { - const GnssMetadata::Lump& lump; - const GnssMetadata::IonStream& stream; - int output_index = -1; - }; - std::vector streams_; - - void* buffer_; -}; - -class IONMetadataStdFileSource : public gr::sync_block -{ -public: - using sptr = gnss_shared_ptr; - - IONMetadataStdFileSource( - const std::filesystem::path& metadata_filepath, - const GnssMetadata::File& file, - const GnssMetadata::Block& block, - const std::vector& 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, const std::vector& stream_ids); - -private: - const GnssMetadata::File& file_metadata_; - const GnssMetadata::Block& block_metadata_; - FILE* fd_; - std::size_t output_stream_count_; - std::vector output_stream_item_sizes_; - std::vector> chunk_data_; -}; - -class GnssMetadataHandler -{ -public: - explicit GnssMetadataHandler(const std::string& metadata_filepath); - - std::vector make_stream_sources(const std::vector& 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 diff --git a/src/algorithms/signal_source/libs/ion_gsms.cc b/src/algorithms/signal_source/libs/ion_gsms.cc new file mode 100644 index 000000000..8110b3af1 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms.cc @@ -0,0 +1,123 @@ +/*! + * \file ion_gsms.cc + * \brief GNU Radio block that reads a Block from a file following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * 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 "gnuradio/block.h" +#include "ion_gsms.h" + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include + +#include +#endif + + +IONGSMSFileSource::IONGSMSFileSource( + const std::filesystem::path& metadata_filepath, + const GnssMetadata::File& file, + const GnssMetadata::Block& block, + const std::vector& stream_ids) + : gr::sync_block( + "ion_metadata_standard_source", + gr::io_signature::make(0, 0, 0), + make_output_signature(block, stream_ids)), + file_metadata_(file), + block_metadata_(block) +{ + std::filesystem::path data_filepath = metadata_filepath.parent_path() / file.Url().Value(); + fd_ = std::fopen(data_filepath.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, 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; +} + +IONGSMSFileSource::~IONGSMSFileSource() +{ + std::fclose(fd_); +} + +int IONGSMSFileSource::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) + // { + for (auto& c : chunk_data_) + { + c->read_from_file(fd_); + c->write_to_output(output_items, [&](int output, int nitems) { + produce(output, nitems); + }); + } + // } + return WORK_CALLED_PRODUCE; +} + +std::size_t IONGSMSFileSource::output_stream_count() const +{ + return output_stream_count_; +} + +std::size_t IONGSMSFileSource::output_stream_item_size(std::size_t stream_index) const +{ + return output_stream_item_sizes_[stream_index]; +} + + +gr::io_signature::sptr IONGSMSFileSource::make_output_signature(const GnssMetadata::Block& block, const std::vector& stream_ids) +{ + int nstreams = 0; + std::vector item_sizes{}; + + 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; + })) + { + ++nstreams; + const std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor(); + item_sizes.push_back(bits_to_item_size(sample_bitsize)); + } + } + } + } + + return gr::io_signature::make( + nstreams, + nstreams, + item_sizes); +} + + diff --git a/src/algorithms/signal_source/libs/ion_gsms.h b/src/algorithms/signal_source/libs/ion_gsms.h new file mode 100644 index 000000000..a15206b84 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms.h @@ -0,0 +1,64 @@ +/*! + * \file ion_gsms.h + * \brief GNU Radio block that reads a Block from a file following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * 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_GNSS_SDR_METADATA_STANDARD_H +#define GNSS_SDR_ION_GNSS_SDR_METADATA_STANDARD_H + +#include "gnss_block_interface.h" +#include "ion_gsms_chunk_data.h" +#include +#include +#include +#include + + +class IONGSMSFileSource : public gr::sync_block +{ +public: + using sptr = gnss_shared_ptr; + + IONGSMSFileSource( + const std::filesystem::path& metadata_filepath, + const GnssMetadata::File& file, + const GnssMetadata::Block& block, + const std::vector& stream_ids); + + ~IONGSMSFileSource() 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: + static gr::io_signature::sptr make_output_signature(const GnssMetadata::Block& block, const std::vector& stream_ids); + +private: + const GnssMetadata::File& file_metadata_; + const GnssMetadata::Block& block_metadata_; + FILE* fd_; + std::size_t output_stream_count_; + std::vector output_stream_item_sizes_; + std::vector> chunk_data_; +}; + +#include "ion_gsms_metadata_handler.h" + + +#endif // GNSS_SDR_ION_GNSS_SDR_METADATA_STANDARD_H diff --git a/src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc new file mode 100644 index 000000000..f961772a0 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc @@ -0,0 +1,108 @@ +/*! + * \file ion_gsms_chunk_data.cc + * \brief Holds logic for reading and decoding samples from a chunk + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * 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_gsms_chunk_data.h" +#include + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#endif + +IONGSMSChunkData::IONGSMSChunkData(const GnssMetadata::Chunk& chunk, const std::vector& stream_ids, std::size_t output_stream_offset) + : chunk_(chunk), + sizeword_(chunk_.SizeWord()), + countwords_(chunk_.CountWords()) +{ + with_word_type(sizeword_, [&] + { + buffer_ = new WordType[countwords_]; + }); + + 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, GnssMetadata::encoding_from_string(stream.Encoding()),output_streams + output_stream_offset); + ++output_streams; + const std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor(); + output_stream_item_size_.push_back(bits_to_item_size(sample_bitsize)); + } + else + { + streams_.emplace_back(lump, stream, GnssMetadata::encoding_from_string(stream.Encoding()), -1); + } + } + } + + output_stream_count_ = output_streams; + padding_bitsize_ = total_bitsize - used_bitsize; +} + + +IONGSMSChunkData::~IONGSMSChunkData() +{ + with_word_type(sizeword_, [&] + { + delete[] static_cast(buffer_); + }); +} + +void IONGSMSChunkData::read_from_file(FILE* fd) +{ + std::fread(buffer_, sizeword_, countwords_, fd); +} + +void IONGSMSChunkData::write_to_output(gr_vector_void_star& outputs, const std::function& produce) +{ + with_word_type(sizeword_, [&] + { + unpack_words(outputs, produce); + }); +} + +std::size_t IONGSMSChunkData::output_stream_count() const +{ + return output_stream_count_; +} + +std::size_t IONGSMSChunkData::output_stream_item_size(std::size_t stream_index) const +{ + return output_stream_item_size_[stream_index]; +} + + + +void IONGSMSChunkData::dump_sample(auto value) +{ + static int count = 100; + if (count > 0) + { + --count; + std::cout << "SAMPLE: " << std::bitset<32>(value) << std::endl; + } +} + diff --git a/src/algorithms/signal_source/libs/ion_gsms_chunk_data.h b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.h new file mode 100644 index 000000000..f87a03aef --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.h @@ -0,0 +1,510 @@ +/*! + * \file ion_gsms_chunk_data.h + * \brief Holds logic for reading and decoding samples from a chunk + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * 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 ION_GSM_CHUNK_DATA_H +#define ION_GSM_CHUNK_DATA_H + +#include "GnssMetadata.h" +#include + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#endif + +inline std::size_t bits_to_item_size(const std::size_t bit_count) +{ + if (bit_count <= 8) + { + return 1; + } + if (bit_count <= 16) + { + return 2; + } + if (bit_count <= 32) + { + return 4; + } + if (bit_count <= 64) + { + return 8; + } + + // You are asking too much of this humble processor + LOG(ERROR) << "Item size too large (" << std::to_string(bit_count) << "), returning nonsense."; + return 1; +} + +void with_word_type(const uint8_t word_size, auto&& callback) +{ + switch (word_size) + { + case 1: + callback.template operator()(); + break; + case 2: + callback.template operator()(); + break; + case 4: + callback.template operator()(); + break; + case 8: + callback.template operator()(); + break; + default: + LOG(ERROR) << "Unknown word size (" << std::to_string(word_size) << "), returning nonsense."; + break; + } +} + +namespace GnssMetadata +{ + using StreamEncoding = unsigned char; + + namespace StreamEncodings + { + constexpr unsigned char SIGN = 0; + constexpr unsigned char OB = 1; + constexpr unsigned char SM = 2; + constexpr unsigned char MS = 3; + constexpr unsigned char TC = 4; + constexpr unsigned char OG = 5; + constexpr unsigned char OBA = 6; + constexpr unsigned char SMA = 7; + constexpr unsigned char MSA = 8; + constexpr unsigned char TCA = 9; + constexpr unsigned char OGA = 10; + constexpr unsigned char FP = 11; + } + + inline StreamEncoding encoding_from_string(const std::string& str) + { + if (str == "SIGN") + { + return StreamEncodings::SIGN; + } + if (str == "OB") + { + return StreamEncodings::OB; + } + if (str == "SM") + { + return StreamEncodings::SM; + } + if (str == "MS") + { + return StreamEncodings::MS; + } + if (str == "TC") + { + return StreamEncodings::TC; + } + if (str == "OG") + { + return StreamEncodings::OG; + } + if (str == "OBA") + { + return StreamEncodings::OBA; + } + if (str == "SMA") + { + return StreamEncodings::SMA; + } + if (str == "MSA") + { + return StreamEncodings::MSA; + } + if (str == "TCA") + { + return StreamEncodings::TCA; + } + if (str == "OGA") + { + return StreamEncodings::OGA; + } + if (str == "FP") + { + return StreamEncodings::FP; + } + return 0; + } + + template + inline T two_bit_look_up[11][4] + { + [0] = {}, + [1 /*OB*/] = {-2, -1, 0, 1}, + [2 /*SM*/] = {0, 1, 0, -1}, + [3 /*MS*/] = {0, 0, 1, -1}, + [4 /*TC*/] = {0, 1, -2, -1}, + [5 /*OG*/] = {-2, -1, 1, 0}, + [6 /*OBA*/] = {-3, -1, 1, 3}, + [7 /*SMA*/] = {1, 3, -1, -3}, + [8 /*MSA*/] = {1, -1, 3, -3}, + [9 /*TCA*/] = {1, 3, -3, -1}, + [10 /*OGA*/] = {-3, -1, 3, 1}, + }; + + template + inline T three_bit_look_up[11][8] + { + [0] = {}, + [1 /*OB*/] = {-4, -3, -2, -1, 0, 1, 2, 3}, + [2 /*SM*/] = {0, 1, 2, 3, 0, -1, -2, -3}, + [3 /*MS*/] = {0, 0, 1, -1, 0, 0, 1, -1}, + [4 /*TC*/] = {0, 1, 2, 3, -4, -3, -2, -1}, + [5 /*OG*/] = {-4, -3, -1, -2, 3, 2, 0, 1}, + [6 /*OBA*/] = {-7, -5, -3, -1, 1, 3, 5, 7}, + [7 /*SMA*/] = {1, 3, 5, 7, -1, -3, -5, -7}, + [8 /*MSA*/] = {1, -1, 3, -3, 5, -5, 7, -7}, + [9 /*TCA*/] = {1, 3, 5, 7, -7, -5, -3, -1}, + [10 /*OGA*/] = {-7, -5, -1, -3, 7, 5, 1, 3}, + }; + + template + inline T four_bit_look_up[11][16] + { + [0] = {}, + [1 /*OB*/] = {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}, + [2 /*SM*/] = {0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7}, + [3 /*MS*/] = {0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1}, + [4 /*TC*/] = {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}, + [5 /*OG*/] = {-8, -7, -5, -6, -1, -2, -4, -3, 7, 6, 4, 5, 0, 1, 3, 2}, + [6 /*OBA*/] = {-15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15}, + [7 /*SMA*/] = {1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15}, + [8 /*MSA*/] = {1, -1, 3, -3, 5, -5, 7, -7, 9, -9, 11, -11, 13, -13, 15, -15}, + [9 /*TCA*/] = {1, 3, 5, 7, 9, 11, 13, 15, -15, -13, -11, -9, -7, -5, -3, -1}, + [10 /*OGA*/] = {-15, -13, -9, -11, -1, -3, -7, -5, 15, 13, 9, 11, 1, 3, 7, 5}, + }; + + template + inline T five_bit_look_up[11][32] + { + [0] = {}, + [1 /*OB*/] = {-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + [2 /*SM*/] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15}, + [3 /*MS*/] = {0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1}, + [4 /*TC*/] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1}, + [5 /*OG*/] = {-16, -15, -13, -14, -9, -10, -12, -11, -1, -2, -4, -3, -8, -7, -5, -6, 15, 14, 12, 13, 8, 9, 11, 10, 0, 1, 3, 2, 7, 6, 4, 5}, + [6 /*OBA*/] = {-31, -29, -27, -25, -23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, + [7 /*SMA*/] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, -1, -3, -5, -7, -9, -11, -13, -15, -17, -19, -21, -23, -25, -27, -29, -31}, + [8 /*MSA*/] = {1, -1, 3, -3, 5, -5, 7, -7, 9, -9, 11, -11, 13, -13, 15, -15, 17, -17, 19, -19, 21, -21, 23, -23, 25, -25, 27, -27, 29, -29, 31, -31}, + [9 /*TCA*/] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, -31, -29, -27, -25, -23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1}, + [10 /*OGA*/] = {-31, -29, -25, -27, -17, -19, -23, -21, -1, -3, -7, -5, -15, -13, -9, -11, 31, 29, 25, 27, 17, 19, 23, 21, 1, 3, 7, 5, 15, 13, 9, 11}, + }; +} + +class IONGSMSChunkData +{ +public: + IONGSMSChunkData(const GnssMetadata::Chunk& chunk, const std::vector& stream_ids, std::size_t output_stream_offset); + + ~IONGSMSChunkData(); + + IONGSMSChunkData(const IONGSMSChunkData& rhl) = delete; + IONGSMSChunkData& operator=(const IONGSMSChunkData& rhl) = delete; + + IONGSMSChunkData(IONGSMSChunkData&& rhl) = delete; + IONGSMSChunkData& operator=(IONGSMSChunkData&& rhl) = delete; + + void read_from_file(FILE* fd); + + void write_to_output(gr_vector_void_star& outputs, const std::function& produce); + + std::size_t output_stream_count() const; + std::size_t output_stream_item_size(std::size_t stream_index) const; + +private: + template + struct unpacking_context_t + { + WT* iterator_; + WT current_word_; + uint8_t bitshift_ = 0; + }; + + template + void unpack_words(gr_vector_void_star& outputs, const std::function& produce) + { + WT* data = static_cast(buffer_); + // TODO - Swap endiannes if needed + + unpacking_context_t 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, encoding, output_index] : streams_) + { + if (output_index == -1) + { + skip_stream(ctx, lump, stream); + } + else + { + produce(output_index, write_stream_samples(ctx, lump, stream, encoding, outputs[output_index])); + } + } + } + + template + void skip_stream( + unpacking_context_t& ctx, + const GnssMetadata::Lump& lump, + const GnssMetadata::IonStream& stream) + { + shift_padding(ctx, stream.Packedbits()); + } + + template + std::size_t write_stream_samples( + unpacking_context_t& ctx, + const GnssMetadata::Lump& lump, + const GnssMetadata::IonStream& stream, + const GnssMetadata::StreamEncoding stream_encoding, + void*& out) + { + std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor(); + std::size_t sample_count = stream.RateFactor(); + + if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization()) + { + // Samples have 'Complex' format + sample_bitsize /= 2; + sample_count *= 2; + } + + if (sample_bitsize <= 8) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, out); + } + else if (sample_bitsize <= 16) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, out); + } + else if (sample_bitsize <= 32) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, out); + } + else if (sample_bitsize <= 64) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, out); + } + + return sample_count; + } + + template + void write_n_samples( + unpacking_context_t& ctx, + GnssMetadata::Lump::LumpShift lump_shift, + uint8_t sample_bitsize, + std::size_t sample_count, + GnssMetadata::StreamEncoding stream_encoding, + void*& out) + { + if (lump_shift == GnssMetadata::Lump::shiftRight) + { + auto* sample = static_cast(out); + sample += sample_count; + for (std::size_t i = 0; i < sample_count; ++i) + { + shift_sample(ctx, sample_bitsize, sample); + decode_sample(sample_bitsize, sample, stream_encoding); + --sample; + } + } + else // if (lump_shift == GnssMetadata::Lump::shiftLeft || lump_shift == GnssMetadata::Lump::shiftUndefined) + { + auto* sample = static_cast(out); + for (std::size_t i = 0; i < sample_count; ++i) + { + shift_sample(ctx, sample_bitsize, sample); + decode_sample(sample_bitsize, sample, stream_encoding); + ++sample; + } + } + } + + template + void shift_sample(unpacking_context_t& 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); + dump_sample(ctx.current_word_ & mask); + *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); + dump_sample(ctx.current_word_ & mask); + *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); + OT sample = (ctx.current_word_ & mask) >> (word_bitsize - sample_bitsize); + dump_sample(sample); + *output |= (sample) >> output_bit_offset; + ctx.current_word_ <<= sample_bitsize; + } + else if (chunk_.Shift() == GnssMetadata::Chunk::Right) + { + WT mask = ((1 << (sample_bitsize)) - 1); + dump_sample(ctx.current_word_ & mask); + *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 + void shift_padding(unpacking_context_t& ctx, uint8_t n_bits) + { + if(n_bits == 0) return; + + 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 + void advance_word(unpacking_context_t& 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; + } + + template + static void decode_sample(const uint8_t sample_bitsize, ST* sample, const GnssMetadata::StreamEncoding encoding) + { + switch (sample_bitsize) + { + case 2: + *sample = GnssMetadata::two_bit_look_up[encoding][*sample]; + break; + case 3: + *sample = GnssMetadata::three_bit_look_up[encoding][*sample]; + break; + case 4: + *sample = GnssMetadata::four_bit_look_up[encoding][*sample]; + break; + case 5: + *sample = GnssMetadata::five_bit_look_up[encoding][*sample]; + break; + default: + // TODO - Is this an error that can happen? + break; + } + } + + static void dump_sample(auto value); + +private: + const GnssMetadata::Chunk& chunk_; + uint8_t sizeword_; + uint8_t countwords_; + uint8_t padding_bitsize_; + std::size_t output_stream_count_; + std::vector output_stream_item_size_; + + struct stream_metadata_t + { + const GnssMetadata::Lump& lump; + const GnssMetadata::IonStream& stream; + GnssMetadata::StreamEncoding stream_encoding; + int output_index = -1; + }; + std::vector streams_; + + void* buffer_; +}; + +#endif //ION_GSM_CHUNK_DATA_H diff --git a/src/algorithms/signal_source/libs/ion_gsms_metadata_handler.cc b/src/algorithms/signal_source/libs/ion_gsms_metadata_handler.cc new file mode 100644 index 000000000..48aced035 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_metadata_handler.cc @@ -0,0 +1,101 @@ +/*! + * \file ion_gsms_metadata_handler.cc + * \brief Build instances of IONGSMSFileSource as needed given a list of stream ids + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * 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_gsms.h" + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#endif + +IONGSMSMetadataHandler::IONGSMSMetadataHandler(const std::string& metadata_filepath) + : metadata_filepath_(metadata_filepath) +{ + load_metadata(); +} + +const std::string& IONGSMSMetadataHandler::metadata_filepath() const +{ + return metadata_filepath_; +} + +void IONGSMSMetadataHandler::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 IONGSMSMetadataHandler::make_stream_sources(const std::vector& stream_ids) const +{ + std::vector sources{}; + for (const auto& file : metadata_.Files()) + { + for (const auto& lane : metadata_.Lanes()) + { + if (lane.Id() == file.Lane().Id()) + { + for (const auto& block : 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( + metadata_filepath_, + 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: + } + break; + } + } + } + + return sources; +} + diff --git a/src/algorithms/signal_source/libs/ion_gsms_metadata_handler.h b/src/algorithms/signal_source/libs/ion_gsms_metadata_handler.h new file mode 100644 index 000000000..0cbf634f6 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_metadata_handler.h @@ -0,0 +1,47 @@ +/*! + * \file ion_gsms_metadata_handler.h + * \brief Build instances of IONGSMSFileSource as needed given a list of stream ids + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * 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 ION_GSMS_METADATA_HANDLER_H +#define ION_GSMS_METADATA_HANDLER_H + +#include "GnssMetadata.h" +#include + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#endif + +class IONGSMSMetadataHandler +{ +public: + explicit IONGSMSMetadataHandler(const std::string& metadata_filepath); + + std::vector make_stream_sources(const std::vector& stream_ids) const; + +public: // Getters + const std::string& metadata_filepath() const; + +private: // Private methods + void load_metadata(); + +private: // State + std::string metadata_filepath_; + GnssMetadata::Metadata metadata_; +}; + +#endif //ION_GSMS_METADATA_HANDLER_H diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 69406a711..99a05e95c 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -93,6 +93,7 @@ #include "ibyte_to_complex.h" #include "ibyte_to_cshort.h" #include "in_memory_configuration.h" +#include "ion_gsms_signal_source.h" #include "ishort_to_complex.h" #include "ishort_to_cshort.h" #include "labsat_signal_source.h" @@ -113,7 +114,6 @@ #include "tracking_interface.h" #include "two_bit_cpx_file_signal_source.h" #include "two_bit_packed_file_signal_source.h" -#include "ion_gnss_ms_signal_source.h" #include // for exit #include // for exception #include // for cerr @@ -760,9 +760,9 @@ std::unique_ptr GNSSBlockFactory::GetBlock( block = std::move(block_); } #endif - else if (implementation == "ION_Metadata_Standard_Signal_Source") + else if (implementation == "ION_GSMS_Signal_Source") { - std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams, queue); block = std::move(block_); }