1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-08-07 22:43:52 +00:00

feat: refactored configuration & renamed to sensor data

This commit is contained in:
Victor Castillo 2025-06-04 15:57:35 +02:00 committed by Carles Fernandez
parent 53006b4ea6
commit 4db7f775b5
24 changed files with 854 additions and 271 deletions

View File

@ -1988,34 +1988,9 @@ void rtklib_pvt_gs::update_HAS_corrections()
int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items __attribute__((unused)))
{
// *************** time tags ****************
if (d_enable_rx_clock_correction == false) // todo: currently only works if clock correction is disabled
{
std::vector<gr::tag_t> tags_vec;
// time tag from obs to pvt is always propagated in channel 0
this->get_tags_in_range(tags_vec, 0, this->nitems_read(0), this->nitems_read(0) + noutput_items, pmt::mp("timetag"));
for (const auto& it : tags_vec)
{
try
{
if (pmt::any_ref(it.value).type().hash_code() == typeid(const std::shared_ptr<GnssTime>).hash_code())
{
const auto timetag = wht::any_cast<const std::shared_ptr<GnssTime>>(pmt::any_ref(it.value));
// std::cout << "PVT timetag: " << timetag->rx_time << '\n';
d_TimeChannelTagTimestamps.push(*timetag);
}
else
{
std::cout << "hash code not match\n";
}
}
catch (const wht::bad_any_cast& e)
{
std::cout << "msg Bad any_cast: " << e.what();
}
}
}
// ************ end time tags **************
std::vector<gr::tag_t> sensor_tags;
this->get_tags_in_range(sensor_tags, 0, this->nitems_read(0), this->nitems_read(0) + noutput_items, pmt::mp("sensor_data"));
SensorDataAggregator sensor_data{sensor_tags};
for (int32_t epoch = 0; epoch < noutput_items; epoch++)
{

View File

@ -662,20 +662,20 @@ void hybrid_observables_gs::set_tag_timestamp_in_sdr_timeframe(const std::vector
}
}
void hybrid_observables_gs::propagate_extra_data(const std::vector<Gnss_Synchro> &data)
void hybrid_observables_gs::propagate_sensor_data(const std::vector<Gnss_Synchro> &data)
{
if (d_extra_data_tags.empty())
if (d_sensor_data_tags.empty())
{
return;
}
do
{
auto &tag = d_extra_data_tags.front();
auto &tag = d_sensor_data_tags.front();
add_item_tag(0, this->nitems_written(0) + 1, tag.key, tag.value);
d_extra_data_tags.pop();
d_sensor_data_tags.pop();
}
while (!d_extra_data_tags.empty());
while (!d_sensor_data_tags.empty());
}
@ -693,16 +693,16 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused)
d_Rx_clock_buffer.push_back(in[d_nchannels_in - 1][0].Tracking_sample_counter);
std::vector<gr::tag_t> tags_vec;
// extra data tags
get_tags_in_range(tags_vec, d_nchannels_in - 1, this->nitems_read(d_nchannels_in - 1), this->nitems_read(d_nchannels_in - 1) + 1, pmt::mp("extra_data"));
// sensor data tags
get_tags_in_range(tags_vec, d_nchannels_in - 1, this->nitems_read(d_nchannels_in - 1), this->nitems_read(d_nchannels_in - 1) + 1, pmt::mp("sensor_data"));
// std::cout << "OBS (" << std::to_string(tags_vec.size()) << ")" << std::endl;
while (!d_extra_data_tags.empty())
while (!d_sensor_data_tags.empty())
{
d_extra_data_tags.pop();
d_sensor_data_tags.pop();
}
for (const auto &tag : tags_vec)
{
d_extra_data_tags.emplace(tag);
d_sensor_data_tags.emplace(tag);
}
// time tags
tags_vec.clear();
@ -829,7 +829,7 @@ int hybrid_observables_gs::general_work(int noutput_items __attribute__((unused)
{
compute_pranges(epoch_data);
set_tag_timestamp_in_sdr_timeframe(epoch_data, d_Rx_clock_buffer.front());
propagate_extra_data(epoch_data);
propagate_sensor_data(epoch_data);
}
// Carrier smoothing (optional)

View File

@ -80,7 +80,7 @@ private:
void set_tag_timestamp_in_sdr_timeframe(const std::vector<Gnss_Synchro>& data, uint64_t rx_clock);
void propagate_extra_data(const std::vector<Gnss_Synchro> &data);
void propagate_sensor_data(const std::vector<Gnss_Synchro> &data);
int32_t save_matfile() const;
@ -93,7 +93,7 @@ private:
std::vector<std::queue<GnssTime>> d_SourceTagTimestamps;
std::queue<GnssTime> d_TimeChannelTagTimestamps;
std::queue<gr::tag_t> d_extra_data_tags;
std::queue<gr::tag_t> d_sensor_data_tags;
std::vector<bool> d_channel_last_pll_lock;
std::vector<double> d_channel_last_pseudorange_smooth;

View File

@ -61,14 +61,7 @@ FileSourceBase::FileSourceBase(ConfigurationInterface const* configuration, std:
repeat_(configuration->property(role_ + ".repeat"s, false)),
enable_throttle_control_(configuration->property(role_ + ".enable_throttle_control"s, false)),
dump_(configuration->property(role_ + ".dump"s, false)),
// Configuration for attaching extra data to the sample stream
attach_extra_data_(configuration->property(role_ + ".extra_data.enabled"s, false)),
ed_path_(configuration->property(role_ + ".extra_data.filename"s, "../data/extra_data.dat"s)),
ed_offset_in_file_(configuration->property(role_ + ".extra_data.file_offset"s, 0UL)),
ed_item_size_(configuration->property(role_ + ".extra_data.item_size"s, 1UL)),
ed_repeat_(configuration->property(role_ + ".extra_data.repeat"s, false)),
ed_offset_in_samples_(configuration->property(role_ + ".extra_data.sample_offset"s, 0UL)),
ed_sample_period_(configuration->property(role_ + ".extra_data.sample_period"s, 1UL))
sensor_data_source_configuration_(configuration, configuration->property(role_ + ".sensor_data.enabled"s, false))
{
minimum_tail_s_ = std::max(configuration->property("Acquisition_1C.coherent_integration_time_ms", 0.0) * 0.001 * 2.0, minimum_tail_s_);
minimum_tail_s_ = std::max(configuration->property("Acquisition_2S.coherent_integration_time_ms", 0.0) * 0.001 * 2.0, minimum_tail_s_);
@ -165,7 +158,7 @@ void FileSourceBase::init()
create_throttle();
create_valve();
create_sink();
create_extra_data_source();
create_sensor_data_source();
}
@ -215,11 +208,11 @@ void FileSourceBase::connect(gr::top_block_sptr top_block)
}
// EXTRA DATA
if (extra_data_source())
if (sensor_data_source())
{
top_block->connect(std::move(output), 0, extra_data_source(), 0);
top_block->connect(std::move(output), 0, sensor_data_source(), 0);
DLOG(INFO) << "connected output to extra data source, which now becomes the new output";
output = extra_data_source();
output = sensor_data_source();
}
post_connect_hook(std::move(top_block));
@ -271,12 +264,12 @@ void FileSourceBase::disconnect(gr::top_block_sptr top_block)
}
// EXTRA DATA
if (extra_data_source())
if (sensor_data_source())
{
// TODO - FIXME: This is NOT okay, `output` is the extra data source, not the valve/source/throttle/whatever is left of this
top_block->disconnect(std::move(output), 0, extra_data_source(), 0);
top_block->disconnect(std::move(output), 0, sensor_data_source(), 0);
DLOG(INFO) << "disconnected output to extra data source";
output = extra_data_source();
output = sensor_data_source();
}
post_disconnect_hook(std::move(top_block));
@ -295,7 +288,7 @@ gr::basic_block_sptr FileSourceBase::get_right_block()
// clang-tidy wants braces around the if-conditions. clang-format wants to break the braces into
// multiple line blocks. It's much more readable this way
// clang-format off
if (extra_data_source_) { return extra_data_source_; }
if (sensor_data_source_) { return sensor_data_source_; }
if (valve_) { return valve_; }
if (throttle_) { return throttle_; }
return source();
@ -504,7 +497,7 @@ gnss_shared_ptr<gr::block> FileSourceBase::file_source() const { return file_sou
gnss_shared_ptr<gr::block> FileSourceBase::valve() const { return valve_; }
gnss_shared_ptr<gr::block> FileSourceBase::throttle() const { return throttle_; }
gnss_shared_ptr<gr::block> FileSourceBase::sink() const { return sink_; }
ExtraDataSource::sptr FileSourceBase::extra_data_source() const { return extra_data_source_; }
SensorDataSource::sptr FileSourceBase::sensor_data_source() const { return sensor_data_source_; }
gr::blocks::file_source::sptr FileSourceBase::create_file_source()
@ -601,25 +594,23 @@ gr::blocks::file_sink::sptr FileSourceBase::create_sink()
return sink_;
}
ExtraDataSource::sptr FileSourceBase::create_extra_data_source()
SensorDataSource::sptr FileSourceBase::create_sensor_data_source()
{
if (attach_extra_data_)
if (sensor_data_source_configuration_.is_enabled())
{
extra_data_source_ = std::make_shared<ExtraDataSource>(
ed_path_,
ed_offset_in_file_,
ed_item_size_,
ed_repeat_,
ed_offset_in_samples_,
ed_sample_period_,
if (is_complex_)
{
sensor_data_source_configuration_.set_items_per_sample(2);
}
sensor_data_source_ = std::make_shared<SensorDataSource>(
sensor_data_source_configuration_,
gr::io_signature::make(1, 1, item_size_));
DLOG(INFO) << "extra_data_source(" << extra_data_source_->unique_id() << ")";
DLOG(INFO) << "sensor_data_source(" << sensor_data_source_->unique_id() << ")";
}
return extra_data_source_;
return sensor_data_source_;
}
// Subclass hooks to augment created objects, as required
void FileSourceBase::create_file_source_hook() {}
void FileSourceBase::create_throttle_hook() {}

View File

@ -19,6 +19,7 @@
#define GNSS_SDR_FILE_SOURCE_BASE_H
#include "concurrent_queue.h"
#include "sensor_data_source.h"
#include "signal_source_base.h"
#include <gnuradio/blocks/file_sink.h> // for dump
#include <gnuradio/blocks/file_source.h>
@ -28,7 +29,6 @@
#include <string>
#include <tuple>
#include "extra_data_source.h"
/** \addtogroup Signal_Source
* \{ */
@ -133,7 +133,7 @@ protected:
gnss_shared_ptr<gr::block> valve() const;
gnss_shared_ptr<gr::block> throttle() const;
gnss_shared_ptr<gr::block> sink() const;
ExtraDataSource::sptr extra_data_source() const;
SensorDataSource::sptr sensor_data_source() const;
// The methods create the various blocks, if enabled, and return access to them. The created
// object is also held in this class
@ -141,7 +141,7 @@ protected:
gr::blocks::throttle::sptr create_throttle();
gnss_shared_ptr<gr::block> create_valve();
gr::blocks::file_sink::sptr create_sink();
ExtraDataSource::sptr create_extra_data_source();
SensorDataSource::sptr create_sensor_data_source();
// Subclass hooks to augment created objects, as required
virtual void create_file_source_hook();
@ -159,7 +159,7 @@ private:
gr::blocks::file_source::sptr file_source_;
gr::blocks::throttle::sptr throttle_;
gr::blocks::file_sink::sptr sink_;
ExtraDataSource::sptr extra_data_source_;
SensorDataSource::sptr sensor_data_source_;
// The valve allows only the configured number of samples through, then it closes.
@ -186,13 +186,7 @@ private:
bool dump_;
// Configuration for Extra Data source
bool attach_extra_data_;
std::string ed_path_;
std::size_t ed_offset_in_file_;
std::size_t ed_item_size_;
bool ed_repeat_;
std::size_t ed_offset_in_samples_;
std::size_t ed_sample_period_;
SensorDataSourceConfiguration sensor_data_source_configuration_;
};
/** \} */

View File

@ -31,7 +31,7 @@ set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
unpack_2bit_samples.cc
unpack_spir_gss6450_samples.cc
labsat23_source.cc
extra_data_source.cc
sensor_data_source.cc
${OPT_DRIVER_SOURCES}
)
@ -46,7 +46,7 @@ set(SIGNAL_SOURCE_GR_BLOCKS_HEADERS
unpack_2bit_samples.h
unpack_spir_gss6450_samples.h
labsat23_source.h
extra_data_source.h
sensor_data_source.h
${OPT_DRIVER_HEADERS}
)

View File

@ -1,82 +0,0 @@
/*!
* \file extra_data_source.cc
* \brief GNURadio block that adds extra data to the sample stream.
* \author Victor Castillo, 2024. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "extra_data_source.h"
#include <pmt/pmt.h>
ExtraDataSource::ExtraDataSource(
const std::string& path,
const std::size_t& offset_in_file,
const std::size_t& item_size,
const bool& repeat,
const std::size_t& offset_in_samples,
const std::size_t& sample_period,
const gr::io_signature::sptr& io_signature
)
: gr::sync_block("Extra Data Source",
io_signature, io_signature),
extra_data_file_(
path,
offset_in_file,
item_size,
repeat),
offset_in_samples_(offset_in_samples),
sample_period_(sample_period),
next_tagged_sample_(offset_in_samples_)
{
if (io_signature->min_streams() != 1 and io_signature->max_streams() != 1)
{
std::cout << "ERROR: This block only supports adding data to a single stream." << "\n";
}
}
std::vector<uint8_t> ExtraDataSource::get_next_item()
{
return extra_data_file_.read_item();
}
std::size_t ExtraDataSource::get_offset_in_samples() const
{
return offset_in_samples_;
}
std::size_t ExtraDataSource::get_sample_period() const
{
return sample_period_;
}
int ExtraDataSource::work(int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items)
{
const std::size_t ch = 0;
const int item_size = input_signature()->sizeof_stream_item(ch);
std::memcpy(output_items[ch], input_items[ch], noutput_items * item_size);
const uint64_t total_items_written = nitems_written(ch) + noutput_items;
if (total_items_written >= next_tagged_sample_)
{
for (uint64_t sample = next_tagged_sample_; sample < total_items_written; sample += sample_period_)
{
auto extra_data_item = get_next_item();
add_item_tag(ch, sample, pmt::mp("extra_data"), pmt::init_u8vector(extra_data_item.size(), extra_data_item));
next_tagged_sample_ += sample_period_;
}
}
return noutput_items;
}

View File

@ -1,72 +0,0 @@
/*!
* \file extra_data_source.h
* \brief GNURadio block that adds extra data to the sample stream.
* \author Victor Castillo, 2024. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_EXTRA_DATA_SOURCE_H
#define GNSS_SDR_EXTRA_DATA_SOURCE_H
#include "gnss_block_interface.h"
#include "extra_data_file.h"
#include <gnuradio/sync_block.h> // for sync_block
#include <gnuradio/types.h> // for gr_vector_const_void_star
#include <cstddef> // for size_t
#include <cstdint>
#include <string>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_gnuradio_blocks
* \{ */
class ExtraDataSource: public gr::sync_block
{
public:
using sptr = gnss_shared_ptr<ExtraDataSource>;
ExtraDataSource(
const std::string& path,
const std::size_t& offset_in_file,
const std::size_t& item_size,
const bool& repeat,
const std::size_t& offset_in_samples,
const std::size_t& sample_period,
const gr::io_signature::sptr& io_signature);
private:
std::vector<uint8_t> get_next_item();
std::size_t get_offset_in_samples() const;
std::size_t get_sample_period() const;
public:
int work(int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items) override;
private:
ExtraDataFile extra_data_file_;
std::size_t offset_in_samples_;
std::size_t sample_period_;
std::size_t next_tagged_sample_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_EXTRA_DATA_SOURCE_H

View File

@ -0,0 +1,113 @@
/*!
* \file sensor_data_source.cc
* \brief GNURadio block that adds extra data to the sample stream.
* \author Victor Castillo, 2024. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "sensor_data_source.h"
#include "sensor_data_file.h"
#include <pmt/pmt.h>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
SensorDataSource::SensorDataSource(
const SensorDataSourceConfiguration& configuration,
const gr::io_signature::sptr& io_signature)
: gr::sync_block("Sensor Data Source",
io_signature, io_signature),
sensor_data_files_({}),
item_size_(io_signature->sizeof_stream_item(0)),
items_per_sample_(configuration.get_items_per_sample())
{
// Open needed data files
for (const auto& file_pair : configuration.files())
{
const auto& id = file_pair.first;
const auto& file = file_pair.second;
std::size_t s_offset = file.sample_offset;
std::size_t s_period = file.sample_period;
if (items_per_sample_ != 1)
{
s_offset *= items_per_sample_;
s_period *= items_per_sample_;
}
sensor_data_files_.emplace(id, std::make_shared<SensorDataFile>(file.filename, s_offset, s_period, file.file_offset, file.chunk_size, file.repeat));
if (not sensor_config_map_.contains(id))
{
sensor_config_map_[id] = {};
}
}
// Populate sensor map (groups sensors by file ID)
for (const auto& sensor : configuration.sensors())
{
sensor_config_map_.at(sensor.file_id).emplace_back(sensor);
}
// Sort lists in sensor map by byte offset within chunk
for (auto& it : sensor_config_map_)
{
auto& sensors_in_file = it.second;
std::sort(sensors_in_file.begin(), sensors_in_file.end(), [](const SensorDataConfiguration& lhs, const SensorDataConfiguration& rhs) -> bool {
return lhs.offset < rhs.offset;
});
}
// Validate IO signature
if (io_signature->min_streams() != 1 and io_signature->max_streams() != 1)
{
std::cout << "ERROR: This block only supports adding data to a single stream." << "\n";
}
}
int SensorDataSource::work(int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items)
{
std::memcpy(output_items[0], input_items[0], noutput_items * item_size_);
const uint64_t total_items_written = nitems_written(0) + noutput_items;
std::size_t sample_stamp;
std::vector<uint8_t> chunk{};
pmt::pmt_t tag_key = pmt::mp("sensor_data");
pmt::pmt_t chunk_count_key = pmt::mp("CHUNK_COUNT");
pmt::pmt_t sample_stamp_key = pmt::mp("SAMPLE_STAMP");
for (auto& file_pair : sensor_data_files_)
{
const auto& file_id = file_pair.first;
auto& data_file = file_pair.second;
while (data_file->read_until_sample(total_items_written, sample_stamp, chunk))
{
pmt::pmt_t data_tag = pmt::make_dict();
data_tag = pmt::dict_add(data_tag, sample_stamp_key, pmt::from_long(sample_stamp / items_per_sample_));
data_tag = pmt::dict_add(data_tag, chunk_count_key, pmt::from_long(data_file->get_chunks_read()));
for (const auto& sensor : sensor_config_map_.at(file_id))
{
data_tag = pmt::dict_add(data_tag, sensor.tag_key, SensorDataType::make_value(sensor.type, &chunk[sensor.offset]));
}
add_item_tag(0, sample_stamp, tag_key, data_tag);
}
}
return noutput_items;
}

View File

@ -0,0 +1,108 @@
/*!
* \file sensor_data_source.h
* \brief GNURadio block that adds extra data to the sample stream.
* \author Victor Castillo, 2024. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_SENSOR_DATA_SOURCE_H
#define GNSS_SDR_SENSOR_DATA_SOURCE_H
#include "gnss_block_interface.h"
#include "sensor_data_file.h"
#include "sensor_data_source_configuration.h"
#include <gnuradio/sync_block.h> // for sync_block
#include <gnuradio/types.h> // for gr_vector_const_void_star
#include <cstddef> // for size_t
#include <cstdint>
#include <string>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_gnuradio_blocks
* \{ */
class SensorDataSource : public gr::sync_block
{
public:
using sptr = gnss_shared_ptr<SensorDataSource>;
SensorDataSource(
const SensorDataSourceConfiguration& configuration,
const gr::io_signature::sptr& io_signature);
int work(int noutput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items) override;
private:
std::unordered_map<SensorDataFile::id_type, SensorDataFile::sptr> sensor_data_files_;
std::unordered_map<SensorDataFile::id_type, std::vector<SensorDataConfiguration>> sensor_config_map_;
std::size_t item_size_;
std::size_t items_per_sample_;
};
class SensorDataAggregator
{
public:
explicit SensorDataAggregator(std::vector<gr::tag_t> tags)
{
for (const auto& sensor_tag : tags)
{
if (sensor_tag.value->is_dict())
{
append_data(sensor_tag.value);
}
}
}
auto get(SensorIdentifier::value_type sensor_id) const
{
if (data_.contains(sensor_id))
{
return data_.at(sensor_id);
}
else
{
return {};
}
}
private:
void append_data(const pmt::pmt_t& data)
{
pmt::pmt_t data_list = pmt::dict_items(data);
while (not pmt::is_null(data_list))
{
pmt::pmt_t pair = pmt::car(data_list);
pmt::pmt_t key = pmt::car(pair);
pmt::pmt_t val = pmt::cdr(pair);
std::string key_str = pmt::write_string(key);
SensorIdentifier::value_type sensor_id = SensorIdentifier::from_string(key_str);
if (not data_.contains(sensor_id))
{
data_[sensor_id] = {};
}
data_[sensor_id].emplace_back(val);
}
}
std::unordered_map<SensorIdentifier::value_type, std::vector<pmt::pmt_t>> data_{};
};
/** \} */
/** \} */
#endif // GNSS_SDR_SENSOR_DATA_SOURCE_H

View File

@ -56,7 +56,10 @@ set(SIGNAL_SOURCE_LIB_SOURCES
rtl_tcp_dongle_info.cc
gnss_sdr_valve.cc
gnss_sdr_timestamp.cc
extra_data_file.cc
sensor_data_file.cc
sensor_data_source_configuration.cc
sensor_data_type.cc
sensor_identifier.cc
${OPT_SIGNAL_SOURCE_LIB_SOURCES}
)
@ -64,7 +67,10 @@ set(SIGNAL_SOURCE_LIB_HEADERS
rtl_tcp_commands.h
rtl_tcp_dongle_info.h
gnss_sdr_valve.h
extra_data_file.h
sensor_data_file.h
sensor_data_source_configuration.h
sensor_data_type.h
sensor_identifier.h
${OPT_SIGNAL_SOURCE_LIB_HEADERS}
)

View File

@ -1,5 +1,5 @@
/*!
* \file extra_data_file.cc
* \file sensor_data_file.cc
* \brief Provides a simple abstraction for reading contiguous binary data from a file
* \author Victor Castillo, 2024. victorcastilloaguero(at).gmail.es
*
@ -14,20 +14,26 @@
* -----------------------------------------------------------------------------
*/
#include "extra_data_file.h"
#include "sensor_data_file.h"
#include <cstring>
ExtraDataFile::ExtraDataFile(
SensorDataFile::SensorDataFile(
const std::string& path,
const std::size_t& sample_delay,
const std::size_t& sample_period,
const std::size_t& offset_in_file,
const std::size_t& item_size,
const bool& repeat)
: path_(path),
file_(path_),
sample_delay_(sample_delay),
sample_period_(sample_period),
offset_in_file_(offset_in_file),
item_size_(item_size),
repeat_(repeat),
done_(false),
chunks_read_(0),
last_sample_stamp_(sample_delay),
io_buffer_size_(item_size * IO_BUFFER_CAPACITY),
offset_in_io_buffer_(io_buffer_size_) // Set to end of buffer so that first look up will trigger a read.
{
@ -36,20 +42,20 @@ ExtraDataFile::ExtraDataFile(
io_buffer_.resize(io_buffer_size_);
}
void ExtraDataFile::reset()
void SensorDataFile::reset()
{
file_.seekg(offset_in_file_, std::ios_base::beg);
offset_in_io_buffer_ = io_buffer_size_;
done_ = false;
}
std::vector<uint8_t> ExtraDataFile::read_item()
bool SensorDataFile::read_item(std::vector<uint8_t>& buffer)
{
if (offset_in_io_buffer_ >= io_buffer_size_)
{
if (done_)
{
return {};
return false;
}
else
{
@ -57,13 +63,30 @@ std::vector<uint8_t> ExtraDataFile::read_item()
}
}
std::vector<uint8_t> item_buf{};
read_into_item_buffer(item_buf);
return item_buf;
chunks_read_++;
read_into_item_buffer(buffer);
return true;
}
void ExtraDataFile::read_into_io_buffer()
bool SensorDataFile::read_until_sample(std::size_t end_sample, std::size_t& sample_stamp, std::vector<uint8_t>& buffer)
{
if (last_sample_stamp_ + sample_period_ < end_sample)
{
last_sample_stamp_ += sample_period_;
sample_stamp = last_sample_stamp_;
read_item(buffer);
return true;
}
return false;
}
std::size_t SensorDataFile::get_chunks_read() const
{
return chunks_read_;
}
void SensorDataFile::read_into_io_buffer()
{
file_.read(reinterpret_cast<char*>(&io_buffer_[0]), io_buffer_size_);
const std::size_t bytes_read = file_.gcount();
@ -85,7 +108,7 @@ void ExtraDataFile::read_into_io_buffer()
offset_in_io_buffer_ = 0;
}
void ExtraDataFile::read_into_item_buffer(std::vector<uint8_t>& item_buf)
void SensorDataFile::read_into_item_buffer(std::vector<uint8_t>& item_buf)
{
item_buf.resize(item_size_);
std::memcpy(item_buf.data(), &io_buffer_[offset_in_io_buffer_], item_size_);

View File

@ -1,5 +1,5 @@
/*!
* \file extra_data_file.h
* \file sensor_data_file.h
* \brief Provides a simple abstraction for reading contiguous binary data from a file
* \author Victor Castillo, 2024. victorcastilloaguero(at).gmail.es
*
@ -15,12 +15,13 @@
*/
#ifndef GNSS_SDR_EXTRA_DATA_FILE_H
#define GNSS_SDR_EXTRA_DATA_FILE_H
#ifndef GNSS_SDR_SENSOR_DATA_FILE_H
#define GNSS_SDR_SENSOR_DATA_FILE_H
#include <cstddef> // for size_t
#include <cstdint>
#include <fstream>
#include <memory>
#include <string>
#include <vector>
@ -30,13 +31,18 @@
* \{ */
class ExtraDataFile
class SensorDataFile
{
static constexpr std::size_t IO_BUFFER_CAPACITY = 1024;
public:
ExtraDataFile(
using sptr = std::shared_ptr<SensorDataFile>;
using id_type = std::size_t;
SensorDataFile(
const std::string& path,
const std::size_t& sample_delay,
const std::size_t& sample_period,
const std::size_t& offset_in_file,
const std::size_t& item_size,
const bool& repeat);
@ -44,9 +50,12 @@ public:
void reset();
std::vector<uint8_t> read_item();
bool read_until_sample(std::size_t end_sample, std::size_t& sample_stamp, std::vector<uint8_t>& buffer);
std::size_t get_chunks_read() const;
private:
bool read_item(std::vector<uint8_t>& buffer);
void read_into_io_buffer();
void read_into_item_buffer(std::vector<uint8_t>& item_buf);
@ -54,11 +63,15 @@ private:
private:
std::string path_;
std::ifstream file_;
std::size_t sample_delay_;
std::size_t sample_period_;
std::size_t offset_in_file_;
std::size_t item_size_;
bool repeat_;
bool done_;
std::size_t chunks_read_;
std::size_t last_sample_stamp_;
std::vector<uint8_t> io_buffer_;
std::size_t io_buffer_size_;
std::size_t offset_in_io_buffer_;
@ -66,4 +79,4 @@ private:
/** \} */
/** \} */
#endif // GNSS_SDR_EXTRA_DATA_FILE_H
#endif // GNSS_SDR_SENSOR_DATA_FILE_H

View File

@ -0,0 +1,152 @@
/*!
* \file sensor_data_source_configuration.cc
* \brief
* \author Victor Castillo, 2025. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "sensor_data_source_configuration.h"
SensorDataSourceConfiguration::SensorDataSourceConfiguration(const ConfigurationInterface* configuration, bool enabled)
: enabled_(enabled), items_per_sample_(1)
{
if (enabled_)
{
configure_files(configuration);
configure_sensors(configuration);
}
}
bool SensorDataSourceConfiguration::validate() const
{
return validate_files() and validate_sensors();
}
bool SensorDataSourceConfiguration::is_enabled() const
{
return enabled_;
}
void SensorDataSourceConfiguration::set_items_per_sample(uint64_t items_per_sample)
{
items_per_sample_ = items_per_sample;
}
uint64_t SensorDataSourceConfiguration::get_items_per_sample() const
{
return items_per_sample_;
}
const std::unordered_map<uint64_t, SensorDataFileConfiguration>& SensorDataSourceConfiguration::files() const
{
return files_;
}
const std::vector<SensorDataConfiguration>& SensorDataSourceConfiguration::sensors() const
{
return sensors_;
}
void SensorDataSourceConfiguration::configure_files(const ConfigurationInterface* configuration)
{
uint64_t file_count = configuration->property(CONFIGURATION_ROLE + ".file_count"s, 1UL);
for (uint64_t id = 0; id < file_count; ++id)
{
std::string role = CONFIGURATION_ROLE + ".file" + std::to_string(id);
files_.emplace(
id,
SensorDataFileConfiguration{
.id = id,
.filename = configuration->property(role + ".filename"s, std::string{""}),
.repeat = configuration->property(role + ".repeat"s, false),
.chunk_size = configuration->property(role + ".chunk_size"s, 0UL),
.file_offset = configuration->property(role + ".file_offset"s, 0UL),
.sample_offset = configuration->property(role + ".sample_offset"s, 0UL),
.sample_period = configuration->property(role + ".sample_period"s, 0UL)});
}
}
void SensorDataSourceConfiguration::configure_sensors(const ConfigurationInterface* configuration)
{
uint64_t sensor_count = configuration->property(CONFIGURATION_ROLE + ".sensor_count"s, 1UL);
for (uint64_t id = 0; id < sensor_count; ++id)
{
std::string role = CONFIGURATION_ROLE + ".sensor" + std::to_string(id);
// Configure sensor data type, default to same data type as previous sensor
SensorDataType::value_type data_type = SensorDataType::FLOAT;
if (id > 0 and not configuration->is_present(role + ".type"))
{
data_type = sensors_[id - 1].type;
}
else
{
data_type = SensorDataType::from_string(configuration->property(role + ".type"s, std::string{"UNKNOWN"}));
}
// Configure offset, default to previous sensor offset plus previous sensor size
uint64_t offset = 0UL;
if (id > 0 and not configuration->is_present(role + ".offset"))
{
offset = sensors_[id - 1].offset + SensorDataType::get_size(sensors_[id - 1].type);
}
else
{
offset = configuration->property(role + ".offset"s, 0UL);
}
// Configure file_id, default to previous sensor file_id
uint64_t file_id = 0UL;
if (id > 0 and not configuration->is_present(role + ".file"))
{
file_id = sensors_[id - 1].file_id;
}
else
{
file_id = configuration->property(role + ".file"s, 0UL);
}
// Find out which sensor this is
const std::string sensor_identifier = configuration->property(role + ".data"s, std::string{"UNDEFINED"});
if (sensor_identifier != "UNDEFINED")
{
sensors_.emplace_back(SensorDataConfiguration{
.id = id,
.file_id = file_id,
.identifier = SensorIdentifier::from_string(sensor_identifier),
.type = data_type,
.offset = offset,
.tag_key = pmt::mp(sensor_identifier)});
}
}
}
bool SensorDataSourceConfiguration::validate_files() const
{
for (const auto& file : files_)
{
// TODO - Implement
}
return true;
}
bool SensorDataSourceConfiguration::validate_sensors() const
{
for (const auto& sensor : sensors_)
{
// TODO - Implement
}
return true;
}

View File

@ -0,0 +1,96 @@
/*!
* \file sensor_data_source_configuration.h
* \brief GNURadio block that adds extra data to the sample stream.
* \author Victor Castillo, 2024. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_SENSOR_DATA_SOURCE_CONFIGURATION_H
#define GNSS_SDR_SENSOR_DATA_SOURCE_CONFIGURATION_H
#include "configuration_interface.h"
#include "sensor_data_type.h"
#include "sensor_identifier.h"
#include <string>
#include <unordered_map>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_gnuradio_blocks
* \{ */
using namespace std::string_literals;
static std::string CONFIGURATION_ROLE = "SensorData";
class ConfigurationInterface;
struct SensorDataFileConfiguration
{
uint64_t id;
std::string filename;
bool repeat;
uint64_t chunk_size;
uint64_t file_offset;
uint64_t sample_offset;
uint64_t sample_period;
};
struct SensorDataConfiguration
{
uint64_t id;
uint64_t file_id;
SensorIdentifier::value_type identifier;
SensorDataType::value_type type;
uint64_t offset;
pmt::pmt_t tag_key;
};
class SensorDataSourceConfiguration
{
public:
explicit SensorDataSourceConfiguration(const ConfigurationInterface* configuration, bool enabled);
bool validate() const;
bool is_enabled() const;
const std::unordered_map<uint64_t, SensorDataFileConfiguration>& files() const;
const std::vector<SensorDataConfiguration>& sensors() const;
void set_items_per_sample(uint64_t items_per_sample);
uint64_t get_items_per_sample() const;
private:
void configure_files(const ConfigurationInterface* configuration);
void configure_sensors(const ConfigurationInterface* configuration);
bool validate_files() const;
bool validate_sensors() const;
private:
bool enabled_;
std::unordered_map<uint64_t, SensorDataFileConfiguration> files_;
std::vector<SensorDataConfiguration> sensors_;
uint64_t items_per_sample_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_SENSOR_DATA_SOURCE_CONFIGURATION_H

View File

@ -0,0 +1,63 @@
/*!
* \file sensor_data_type.cc
* \brief
* \author Victor Castillo, 2025. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "sensor_data_type.h"
#include <cstdint>
#include <pmt/pmt.h>
#include <stdexcept>
#include <string>
SensorDataType::value_type SensorDataType::from_string(const std::string& s)
{
if (s == "float" or s == "FLOAT")
{
return SensorDataType::FLOAT;
}
throw std::runtime_error{"Unknown sensor data type: " + s};
}
std::string SensorDataType::to_string(const SensorDataType::value_type& v)
{
switch (v)
{
case SensorDataType::FLOAT:
return "float";
default:
return "UNKNOWN SENSOR";
}
}
uint64_t SensorDataType::get_size(const SensorDataType::value_type& v)
{
switch (v)
{
case SensorDataType::FLOAT:
return sizeof(float);
default:
return 0UL;
}
}
pmt::pmt_t SensorDataType::make_value(const SensorDataType::value_type& v, void* value)
{
switch (v)
{
case SensorDataType::FLOAT:
return pmt::from_float(*static_cast<float*>(value));
default:
throw std::runtime_error{"Unknown sensor data type: " + to_string(v)};
}
}

View File

@ -0,0 +1,50 @@
/*!
* \file sensor_data_type.h
* \brief
* \author Victor Castillo, 2025. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_SENSOR_DATA_TYPE_H
#define GNSS_SDR_SENSOR_DATA_TYPE_H
#include <cstdint>
#include <pmt/pmt.h>
#include <string>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
struct SensorDataType
{
SensorDataType() = delete;
enum value_type
{
FLOAT
};
static value_type from_string(const std::string& s);
static std::string to_string(const value_type& v);
static uint64_t get_size(const value_type& v);
static pmt::pmt_t make_value(const value_type& v, void* value);
};
/** \} */
/** \} */
#endif // GNSS_SDR_SENSOR_DATA_TYPE_H

View File

@ -0,0 +1,105 @@
/*!
* \file sensor_identifier.cc
* \brief
* \author Victor Castillo, 2025. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "sensor_identifier.h"
#include <stdexcept>
#include <string>
SensorIdentifier::value_type SensorIdentifier::from_string(const std::string& s)
{
if (s == "IMU_VEL_X")
{
return IMU_VEL_X;
}
else if (s == "IMU_VEL_Y")
{
return IMU_VEL_Y;
}
else if (s == "IMU_VEL_Z")
{
return IMU_VEL_Z;
}
else if (s == "IMU_ACC_X")
{
return IMU_ACC_X;
}
else if (s == "IMU_ACC_Y")
{
return IMU_ACC_Y;
}
else if (s == "IMU_ACC_Z")
{
return IMU_ACC_Z;
}
else if (s == "IMU_ANG_VEL_X")
{
return IMU_ANG_VEL_X;
}
else if (s == "IMU_ANG_VEL_Y")
{
return IMU_ANG_VEL_Y;
}
else if (s == "IMU_ANG_VEL_Z")
{
return IMU_ANG_VEL_Z;
}
else if (s == "IMU_ANG_ACC_X")
{
return IMU_ANG_ACC_X;
}
else if (s == "IMU_ANG_ACC_Y")
{
return IMU_ANG_ACC_Y;
}
else if (s == "IMU_ANG_ACC_Z")
{
return IMU_ANG_ACC_Z;
}
throw std::runtime_error{"Unknown sensor identifier: " + s};
}
std::string SensorIdentifier::to_string(const SensorIdentifier::value_type& v)
{
switch (v)
{
case IMU_VEL_X:
return "IMU_VEL_X";
case IMU_VEL_Y:
return "IMU_VEL_Y";
case IMU_VEL_Z:
return "IMU_VEL_Z";
case IMU_ACC_X:
return "IMU_ACC_X";
case IMU_ACC_Y:
return "IMU_ACC_Y";
case IMU_ACC_Z:
return "IMU_ACC_Z";
case IMU_ANG_VEL_X:
return "IMU_ANG_VEL_X";
case IMU_ANG_VEL_Y:
return "IMU_ANG_VEL_Y";
case IMU_ANG_VEL_Z:
return "IMU_ANG_VEL_Z";
case IMU_ANG_ACC_X:
return "IMU_ANG_ACC_X";
case IMU_ANG_ACC_Y:
return "IMU_ANG_ACC_Y";
case IMU_ANG_ACC_Z:
return "IMU_ANG_ACC_Z";
default:
return "UNKNOWN SENSOR";
}
}

View File

@ -0,0 +1,54 @@
/*!
* \file sensor_identifier.h
* \brief
* \author Victor Castillo, 2025. victorcastilloaguero(at).gmail.es
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_SENSOR_IDENTIFIER_H
#define GNSS_SDR_SENSOR_IDENTIFIER_H
#include <string>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
struct SensorIdentifier
{
SensorIdentifier() = delete;
enum value_type
{
IMU_VEL_X,
IMU_VEL_Y,
IMU_VEL_Z,
IMU_ACC_X,
IMU_ACC_Y,
IMU_ACC_Z,
IMU_ANG_VEL_X,
IMU_ANG_VEL_Y,
IMU_ANG_VEL_Z,
IMU_ANG_ACC_X,
IMU_ANG_ACC_Y,
IMU_ANG_ACC_Z,
};
static value_type from_string(const std::string& s);
static std::string to_string(const value_type& v);
};
/** \} */
/** \} */
#endif // GNSS_SDR_SENSOR_IDENTIFIER_H

View File

@ -645,14 +645,7 @@ int gps_l1_ca_telemetry_decoder_gs::general_work(int noutput_items __attribute__
current_symbol.Flag_PLL_180_deg_phase_locked = false;
}
// TODO - Merge these two loops
std::vector<gr::tag_t> tags_vec;
// get_tags_in_range(tags_vec, 0, this->nitems_read(0)-1, this->nitems_read(0), pmt::mp("extra_data"));
// for (const auto & tag : tags_vec)
// {
// add_item_tag(0, this->nitems_written(0) + 1, tag.key, tag.value);
// }
// tags_vec.clear();
// time tags
this->get_tags_in_range(tags_vec, 0, this->nitems_read(0), this->nitems_read(0) + 1, pmt::mp("timetag"));

View File

@ -56,6 +56,7 @@ public:
virtual float property(std::string property_name, float default_value) const = 0;
virtual double property(std::string property_name, double default_value) const = 0;
virtual void set_property(std::string property_name, std::string value) = 0;
virtual bool is_present(const std::string& property_name) const = 0;
};

View File

@ -151,16 +151,16 @@ int gnss_sdr_sample_counter::work(int noutput_items __attribute__((unused)),
out[0].Tracking_sample_counter = sample_counter;
current_T_rx_ms += interval_ms;
// *************** time tags ****************
// *************** sensor tags ****************
std::vector<gr::tag_t> tags_vec;
// notice that nitems_read is updated in decimation blocks after leaving work() with return 1, equivalent to call consume_each
this->get_tags_in_range(tags_vec, 0, this->nitems_read(0), this->nitems_read(0) + samples_per_output, pmt::mp("extra_data"));
// std::cout << "SAMPLE COUNTER (" << std::to_string(tags_vec.size()) << ")" << std::endl;
get_tags_in_range(tags_vec, 0, nitems_read(0), nitems_read(0) + samples_per_output, pmt::mp("sensor_data"));
for (const auto &tag : tags_vec)
{
add_item_tag(0, this->nitems_written(0) + 1, tag.key, tag.value);
add_item_tag(0, nitems_written(0) + 1, tag.key, tag.value);
}
// *************** time tags ****************
tags_vec.clear();
this->get_tags_in_range(tags_vec, 0, this->nitems_read(0), this->nitems_read(0) + samples_per_output, pmt::mp("timetag"));
for (const auto &it : tags_vec)

View File

@ -62,7 +62,7 @@ public:
float property(std::string property_name, float default_value) const override;
double property(std::string property_name, double default_value) const override;
void set_property(std::string property_name, std::string value) override;
bool is_present(const std::string& property_name) const;
bool is_present(const std::string& property_name) const override;
bool has_section() const;
private:

View File

@ -57,7 +57,7 @@ public:
double property(std::string property_name, double default_value) const override;
void set_property(std::string property_name, std::string value) override;
void supersede_property(const std::string& property_name, const std::string& value);
bool is_present(const std::string& property_name) const;
bool is_present(const std::string& property_name) const override;
private:
std::map<std::string, std::string> properties_;