mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-11-11 04:20:03 +00:00
Fixed decoding errors and refactored each class into its own file
This commit is contained in:
parent
598fa283b8
commit
469eaf76e5
@ -119,7 +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
|
ion_gsms_signal_source.cc
|
||||||
${OPT_DRIVER_SOURCES}
|
${OPT_DRIVER_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -139,7 +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
|
ion_gsms_signal_source.h
|
||||||
${OPT_DRIVER_HEADERS}
|
${OPT_DRIVER_HEADERS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file file_timestamp_signal_source.cc
|
* \file ion_gsms_signal_source.h
|
||||||
* \brief This class reads samples stored in a file and generate stream tags
|
* \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard
|
||||||
* with its timestamp information stored in separated file
|
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
|
||||||
* \author Javier Arribas, jarribas(at)cttc.es
|
|
||||||
*
|
*
|
||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
@ -15,9 +14,9 @@
|
|||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ion_gnss_ms_signal_source.h"
|
|
||||||
#include "gnss_sdr_flags.h"
|
#include "gnss_sdr_flags.h"
|
||||||
#include "gnss_sdr_string_literals.h"
|
#include "gnss_sdr_string_literals.h"
|
||||||
|
#include "ion_gsms_signal_source.h"
|
||||||
#include <gnuradio/blocks/copy.h>
|
#include <gnuradio/blocks/copy.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@ -49,7 +48,7 @@ std::vector<std::string> parse_comma_list(const std::string& str)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
IONMetadataStandardSignalSource::IONMetadataStandardSignalSource(const ConfigurationInterface* configuration,
|
IONGSMSSignalSource::IONGSMSSignalSource(const ConfigurationInterface* configuration,
|
||||||
const std::string& role,
|
const std::string& role,
|
||||||
unsigned int in_streams,
|
unsigned int in_streams,
|
||||||
unsigned int out_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)),
|
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))),
|
stream_ids_(parse_comma_list(configuration->property(role + ".streams"s, ""s))),
|
||||||
metadata_(metadata_file_),
|
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)
|
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;
|
std::size_t cumulative_index = 0;
|
||||||
for (const auto& source : sources_)
|
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;
|
std::size_t cumulative_index = 0;
|
||||||
for (const auto& source : sources_)
|
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.";
|
LOG(WARNING) << "Trying to get signal source left block.";
|
||||||
// return gr_basic_block_sptr();
|
// 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);
|
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];
|
return copy_blocks_[RF_channel];
|
||||||
}
|
}
|
@ -1,8 +1,7 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file file_timestamp_signal_source.h
|
* \file ion_gsms_signal_source.h
|
||||||
* \brief This class reads samples stored in a file and generate stream tags
|
* \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard
|
||||||
* with its timestamp information stored in separated file
|
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
|
||||||
* \author Javier Arribas, jarribas(at)cttc.es
|
|
||||||
*
|
*
|
||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
@ -22,7 +21,7 @@
|
|||||||
#include "configuration_interface.h"
|
#include "configuration_interface.h"
|
||||||
#include "file_source_base.h"
|
#include "file_source_base.h"
|
||||||
#include "gnss_sdr_timestamp.h"
|
#include "gnss_sdr_timestamp.h"
|
||||||
#include "ion_gnss_sdr_metadata_standard.h"
|
#include "ion_gsms.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/** \addtogroup Signal_Source
|
/** \addtogroup Signal_Source
|
||||||
@ -34,14 +33,14 @@
|
|||||||
* \brief Class that reads signals samples from a file
|
* \brief Class that reads signals samples from a file
|
||||||
* and adapts it to a SignalSourceInterface
|
* and adapts it to a SignalSourceInterface
|
||||||
*/
|
*/
|
||||||
class IONMetadataStandardSignalSource : public SignalSourceBase
|
class IONGSMSSignalSource : public SignalSourceBase
|
||||||
{
|
{
|
||||||
public:
|
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,
|
unsigned int in_streams, unsigned int out_streams,
|
||||||
Concurrent_Queue<pmt::pmt_t>* queue);
|
Concurrent_Queue<pmt::pmt_t>* queue);
|
||||||
|
|
||||||
~IONMetadataStandardSignalSource() override = default;
|
~IONGSMSSignalSource() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// std::tuple<size_t, bool> itemTypeToSize() override;
|
// std::tuple<size_t, bool> itemTypeToSize() override;
|
||||||
@ -60,9 +59,9 @@ protected:
|
|||||||
private:
|
private:
|
||||||
std::string metadata_file_;
|
std::string metadata_file_;
|
||||||
std::vector<std::string> stream_ids_;
|
std::vector<std::string> stream_ids_;
|
||||||
std::vector<IONMetadataStdFileSource::sptr> sources_;
|
std::vector<IONGSMSFileSource::sptr> sources_;
|
||||||
std::vector<gnss_shared_ptr<gr::block>> copy_blocks_;
|
std::vector<gnss_shared_ptr<gr::block>> copy_blocks_;
|
||||||
GnssMetadataHandler metadata_;
|
IONGSMSMetadataHandler metadata_;
|
||||||
|
|
||||||
gnss_shared_ptr<Gnss_Sdr_Timestamp> timestamp_block_;
|
gnss_shared_ptr<Gnss_Sdr_Timestamp> timestamp_block_;
|
||||||
std::string timestamp_file_;
|
std::string timestamp_file_;
|
@ -46,8 +46,12 @@ if(ENABLE_PLUTOSDR)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_ION)
|
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_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ion_gsms.cc)
|
||||||
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gnss_sdr_metadata_standard.h)
|
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()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,340 +0,0 @@
|
|||||||
//
|
|
||||||
// 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& 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<IONMetadataStdFileSource>(
|
|
||||||
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<std::string>& 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_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, const std::vector<std::string>& stream_ids)
|
|
||||||
{
|
|
||||||
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())
|
|
||||||
{
|
|
||||||
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<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];
|
|
||||||
}
|
|
@ -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 <gnuradio/sync_block.h>
|
|
||||||
#include <string>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
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 std::filesystem::path& metadata_filepath,
|
|
||||||
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, const std::vector<std::string>& stream_ids);
|
|
||||||
|
|
||||||
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
|
|
123
src/algorithms/signal_source/libs/ion_gsms.cc
Normal file
123
src/algorithms/signal_source/libs/ion_gsms.cc
Normal file
@ -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 <glog/logging.h>
|
||||||
|
#else
|
||||||
|
#include <absl/log/log.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
IONGSMSFileSource::IONGSMSFileSource(
|
||||||
|
const std::filesystem::path& metadata_filepath,
|
||||||
|
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, 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<IONGSMSChunkData>(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<std::string>& stream_ids)
|
||||||
|
{
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
64
src/algorithms/signal_source/libs/ion_gsms.h
Normal file
64
src/algorithms/signal_source/libs/ion_gsms.h
Normal file
@ -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 <gnuradio/block.h>
|
||||||
|
#include <gnuradio/sync_block.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
class IONGSMSFileSource : public gr::sync_block
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using sptr = gnss_shared_ptr<IONGSMSFileSource>;
|
||||||
|
|
||||||
|
IONGSMSFileSource(
|
||||||
|
const std::filesystem::path& metadata_filepath,
|
||||||
|
const GnssMetadata::File& file,
|
||||||
|
const GnssMetadata::Block& block,
|
||||||
|
const std::vector<std::string>& 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<std::string>& stream_ids);
|
||||||
|
|
||||||
|
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<IONGSMSChunkData>> chunk_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "ion_gsms_metadata_handler.h"
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GNSS_SDR_ION_GNSS_SDR_METADATA_STANDARD_H
|
108
src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc
Normal file
108
src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc
Normal file
@ -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 <bitset>
|
||||||
|
|
||||||
|
#if USE_GLOG_AND_GFLAGS
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#else
|
||||||
|
#include <absl/log/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IONGSMSChunkData::IONGSMSChunkData(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())
|
||||||
|
{
|
||||||
|
with_word_type(sizeword_, [&]<typename WordType>
|
||||||
|
{
|
||||||
|
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_, [&]<typename WordType>
|
||||||
|
{
|
||||||
|
delete[] static_cast<WordType*>(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<void(int output, int nitems)>& produce)
|
||||||
|
{
|
||||||
|
with_word_type(sizeword_, [&]<typename WordType>
|
||||||
|
{
|
||||||
|
unpack_words<WordType>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
510
src/algorithms/signal_source/libs/ion_gsms_chunk_data.h
Normal file
510
src/algorithms/signal_source/libs/ion_gsms_chunk_data.h
Normal file
@ -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 <gnuradio/block.h>
|
||||||
|
|
||||||
|
#if USE_GLOG_AND_GFLAGS
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#else
|
||||||
|
#include <absl/log/log.h>
|
||||||
|
#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()<int8_t>();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
callback.template operator()<int16_t>();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
callback.template operator()<int32_t>();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
callback.template operator()<int64_t>();
|
||||||
|
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 <typename T>
|
||||||
|
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 <typename T>
|
||||||
|
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 <typename T>
|
||||||
|
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 <typename T>
|
||||||
|
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<std::string>& 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<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, 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 <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,
|
||||||
|
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<WT, int8_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, out);
|
||||||
|
}
|
||||||
|
else if (sample_bitsize <= 16)
|
||||||
|
{
|
||||||
|
write_n_samples<WT, int16_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, out);
|
||||||
|
}
|
||||||
|
else if (sample_bitsize <= 32)
|
||||||
|
{
|
||||||
|
write_n_samples<WT, int32_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, out);
|
||||||
|
}
|
||||||
|
else if (sample_bitsize <= 64)
|
||||||
|
{
|
||||||
|
write_n_samples<WT, int64_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, 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,
|
||||||
|
GnssMetadata::StreamEncoding stream_encoding,
|
||||||
|
void*& out)
|
||||||
|
{
|
||||||
|
if (lump_shift == GnssMetadata::Lump::shiftRight)
|
||||||
|
{
|
||||||
|
auto* sample = static_cast<OT*>(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<OT*>(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 <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);
|
||||||
|
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 <typename WT>
|
||||||
|
void shift_padding(unpacking_context_t<WT>& 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 <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;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ST>
|
||||||
|
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<ST>[encoding][*sample];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*sample = GnssMetadata::three_bit_look_up<ST>[encoding][*sample];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*sample = GnssMetadata::four_bit_look_up<ST>[encoding][*sample];
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
*sample = GnssMetadata::five_bit_look_up<ST>[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<std::size_t> 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<stream_metadata_t> streams_;
|
||||||
|
|
||||||
|
void* buffer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //ION_GSM_CHUNK_DATA_H
|
101
src/algorithms/signal_source/libs/ion_gsms_metadata_handler.cc
Normal file
101
src/algorithms/signal_source/libs/ion_gsms_metadata_handler.cc
Normal file
@ -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 <glog/logging.h>
|
||||||
|
#else
|
||||||
|
#include <absl/log/log.h>
|
||||||
|
#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<IONGSMSFileSource::sptr> IONGSMSMetadataHandler::make_stream_sources(const std::vector<std::string>& stream_ids) const
|
||||||
|
{
|
||||||
|
std::vector<IONGSMSFileSource::sptr> 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<IONGSMSFileSource>(
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
@ -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 <gnuradio/block.h>
|
||||||
|
|
||||||
|
#if USE_GLOG_AND_GFLAGS
|
||||||
|
#include <glog/logging.h>
|
||||||
|
#else
|
||||||
|
#include <absl/log/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class IONGSMSMetadataHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IONGSMSMetadataHandler(const std::string& metadata_filepath);
|
||||||
|
|
||||||
|
std::vector<IONGSMSFileSource::sptr> make_stream_sources(const std::vector<std::string>& 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
|
@ -93,6 +93,7 @@
|
|||||||
#include "ibyte_to_complex.h"
|
#include "ibyte_to_complex.h"
|
||||||
#include "ibyte_to_cshort.h"
|
#include "ibyte_to_cshort.h"
|
||||||
#include "in_memory_configuration.h"
|
#include "in_memory_configuration.h"
|
||||||
|
#include "ion_gsms_signal_source.h"
|
||||||
#include "ishort_to_complex.h"
|
#include "ishort_to_complex.h"
|
||||||
#include "ishort_to_cshort.h"
|
#include "ishort_to_cshort.h"
|
||||||
#include "labsat_signal_source.h"
|
#include "labsat_signal_source.h"
|
||||||
@ -113,7 +114,6 @@
|
|||||||
#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
|
||||||
@ -760,9 +760,9 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
|
|||||||
block = std::move(block_);
|
block = std::move(block_);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (implementation == "ION_Metadata_Standard_Signal_Source")
|
else if (implementation == "ION_GSMS_Signal_Source")
|
||||||
{
|
{
|
||||||
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<IONMetadataStandardSignalSource>(configuration, role, in_streams,
|
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<IONGSMSSignalSource>(configuration, role, in_streams,
|
||||||
out_streams, queue);
|
out_streams, queue);
|
||||||
block = std::move(block_);
|
block = std::move(block_);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user