From a6b63c77dc9cf037671f649cc4deefd17a0d8b7b Mon Sep 17 00:00:00 2001 From: joebre Date: Tue, 15 Sep 2026 11:36:38 +0200 Subject: [PATCH] Add EVK1029 file_offset config to seek into a raw capture Evk1029SignalSource.file_offset (seconds, default 0 = disabled) lets a long capture be jumped straight to a time of interest instead of always reprocessed from the start. Converted to a byte count using the source's own sampling frequency, then rounded up to the next 64-bit word boundary in Evk1029Source before seeking, matching the capture's native packing (16 OBA samples per little-endian 64-bit word). --- .../adapters/evk1029_signal_source.cc | 19 +++++++++++-- .../gnuradio_blocks/evk1029_source.cc | 28 +++++++++++++++++-- .../gnuradio_blocks/evk1029_source.h | 18 ++++++++++-- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/algorithms/signal_source/adapters/evk1029_signal_source.cc b/src/algorithms/signal_source/adapters/evk1029_signal_source.cc index d0d1f11be..f3311e330 100644 --- a/src/algorithms/signal_source/adapters/evk1029_signal_source.cc +++ b/src/algorithms/signal_source/adapters/evk1029_signal_source.cc @@ -15,6 +15,7 @@ #include "evk1029_signal_source.h" #include "configuration_interface.h" +#include #include #if USE_GLOG_AND_GFLAGS @@ -46,6 +47,19 @@ Evk1029SignalSource::Evk1029SignalSource( const int64_t default_fs = configuration->property("GNSS-SDR.internal_fs_sps"s, int64_t(0)); const int64_t fs = configuration->property(role + ".sampling_frequency"s, default_fs); + // Lets a long capture be jumped straight to a "time of interest" (e.g. + // to check effective signal strength at a specific point) instead of + // always reprocessed from the start. Expressed in seconds, not bytes -- + // fs (the raw capture's own sample rate) is already known right here, + // so converting is trivial and saves the caller from hand-computing a + // byte count themselves. Two OBA samples are packed per byte, hence the + // /2; Evk1029Source rounds the resulting byte count up to the next + // 64-bit word boundary itself (see its header) before seeking. + const double file_offset_s = configuration->property(role + ".file_offset"s, 0.0); + const auto file_offset_bytes = (file_offset_s > 0.0 && fs > 0) + ? static_cast(std::llround(file_offset_s * static_cast(fs) / 2.0)) + : uint64_t(0); + if (rf_channels_ == 0) { rf_channels_ = 1; @@ -60,9 +74,10 @@ Evk1029SignalSource::Evk1029SignalSource( enable_throttle_control_ = false; } - DLOG(INFO) << "EVK1029 Signal Source: filename=" << filename << ", fs=" << fs << ", item_size=" << item_size_ << ", RF_channels=" << rf_channels_; + DLOG(INFO) << "EVK1029 Signal Source: filename=" << filename << ", fs=" << fs << ", item_size=" << item_size_ + << ", RF_channels=" << rf_channels_ << ", file_offset_s=" << file_offset_s; - evk1029_source_ = evk1029_make_source(filename, static_cast(rf_channels_), queue, static_cast(fs)); + evk1029_source_ = evk1029_make_source(filename, static_cast(rf_channels_), queue, static_cast(fs), file_offset_bytes); if (enable_throttle_control_) { diff --git a/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.cc b/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.cc index e3306ee45..1c00d15f1 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.cc @@ -62,13 +62,13 @@ int output_multiple_from_sampling_frequency(double sampling_frequency) } // namespace -Evk1029Source_sptr evk1029_make_source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency) +Evk1029Source_sptr evk1029_make_source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency, uint64_t file_offset_bytes) { - return Evk1029Source_sptr(new Evk1029Source(filename, n_streams, queue, sampling_frequency)); + return Evk1029Source_sptr(new Evk1029Source(filename, n_streams, queue, sampling_frequency, file_offset_bytes)); } -Evk1029Source::Evk1029Source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency) +Evk1029Source::Evk1029Source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency, uint64_t file_offset_bytes) : gr::sync_block("evk1029_source", gr::io_signature::make(0, 0, 0), gr::io_signature::make(n_streams, n_streams, sizeof(int8_t))), @@ -97,6 +97,28 @@ Evk1029Source::Evk1029Source(const std::string& filename, int n_streams, Concurr std::cerr << "EVK1029_Source: failed to open file: " << filename << '\n'; exit(1); } + + if (file_offset_bytes > 0) + { + // Round up to the next 64-bit (8-byte) word boundary -- see this + // parameter's doc comment in the header for why. + constexpr uint64_t kWordBytes = 8; + const uint64_t aligned_offset = ((file_offset_bytes + kWordBytes - 1) / kWordBytes) * kWordBytes; + + binary_input_file_.seekg(0, std::ios::end); + const auto file_size = static_cast(binary_input_file_.tellg()); + if (aligned_offset >= file_size) + { + std::cerr << "EVK1029_Source: file_offset (" << aligned_offset + << " bytes, aligned) is at or beyond the end of '" << filename + << "' (" << file_size << " bytes) -- nothing to read.\n"; + exit(1); + } + + binary_input_file_.seekg(static_cast(aligned_offset), std::ios::beg); + std::cout << "EVK1029_Source: skipping to file offset " << aligned_offset + << " bytes (requested " << file_offset_bytes << ", rounded up to a 64-bit word boundary).\n"; + } } diff --git a/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.h b/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.h index 178f5ee45..197b39513 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/evk1029_source.h @@ -52,7 +52,19 @@ class Evk1029Source; using Evk1029Source_sptr = gnss_shared_ptr; -Evk1029Source_sptr evk1029_make_source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency); +// file_offset_bytes: byte position in the raw capture to seek to before the +// first read, letting a long capture be jumped straight to a "time of +// interest" instead of always reprocessed from the start (see +// Evk1029SignalSource.file_offset in the adapter, which converts a +// requested offset in seconds -- since the sampling frequency is already +// known there -- into this byte count). Rounded up to the next multiple of +// 8 bytes (64 bits) here, matching the capture's native packing (16 OBA +// samples per little-endian 64-bit word): this block itself only ever reads +// byte-by-byte and would decode correctly from any byte offset, but seeking +// to a non-word-aligned byte splits a 64-bit DMA word the real hardware +// always transferred as one unit, which needlessly complicates comparing a +// jumped-to run against a from-the-start one at the file/word level. +Evk1029Source_sptr evk1029_make_source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency, uint64_t file_offset_bytes = 0); /*! * \brief Reads a continuous, header-less EVK1029 raw capture file and @@ -65,8 +77,8 @@ public: ~Evk1029Source() override; private: - friend Evk1029Source_sptr evk1029_make_source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency); - Evk1029Source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency); + friend Evk1029Source_sptr evk1029_make_source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency, uint64_t file_offset_bytes); + Evk1029Source(const std::string& filename, int n_streams, Concurrent_Queue* queue, double sampling_frequency, uint64_t file_offset_bytes = 0); int work(int noutput_items, gr_vector_const_void_star& input_items,