1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-04 23:40:04 +00:00

Merge branch 'ft/ion-metadata-standard-signal-source' of https://github.com/castle055/gnss-sdr into castle055-ft/ion-metadata-standard-signal-source

This commit is contained in:
Carles Fernandez 2024-08-22 12:10:57 +02:00
commit 52c91fd1ca
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
18 changed files with 1521 additions and 6 deletions

View File

@ -28,7 +28,7 @@ jobs:
libgnutls-openssl-dev libmatio-dev googletest protobuf-compiler libprotobuf-dev \
python3-mako liborc-0.4-dev
- name: configure
run: cd build && cmake -GNinja ..
run: cd build && cmake -GNinja -DENABLE_ION=ON ..
- name: build
run: cd build && ninja
- name: check
@ -60,7 +60,7 @@ jobs:
brew install ninja hdf5 automake armadillo lapack libmatio gnuradio openssl pugixml protobuf
pip3 install mako
- name: configure
run: cd build && cmake -GNinja ..
run: cd build && cmake -GNinja -DENABLE_ION=ON ..
- name: build
run: cd build && ninja
- name: check
@ -92,7 +92,7 @@ jobs:
brew install ninja pkg-config hdf5 automake armadillo lapack libmatio gnuradio openssl pugixml protobuf
pip3 install mako
- name: configure
run: cd build && cmake -GXcode ..
run: cd build && cmake -GXcode -DENABLE_ION=ON ..
- name: build
run: cd build && xcodebuild -configuration Release
- name: check

View File

@ -64,6 +64,7 @@ Marc Sales marcsales92@gmail.com Contributor
Piyush Gupta piyush04111999@gmail.com Contributor
Rodrigo Muñoz rodrigo.munoz@proteinlab.cl Contributor
Stefan van der Linden spvdlinden@gmail.com Contributor
Víctor Castillo-Agüero victorcastilloaguero@gmail.com Contributor
Will Silberman wsilberm@google.com Contributor
Carlos Paniego carpanie@hotmail.com Artwork

View File

@ -34,6 +34,11 @@ authors:
email: mara.branzanti@gmail.com
family-names: Branzanti
given-names: Mara
- alias: castle055
affiliation: "Instituto Nacional de Técnica Aeroespacial"
email: victorcastilloaguero@gmail.com
family-names: "Castillo-Agüero"
given-names: Víctor
- alias: acebrianjuan
email: acebrianjuan@gmail.com
family-names: "Cebrián-Juan"

View File

@ -57,6 +57,8 @@ option(ENABLE_ARRAY "Enable the use of CTTC's antenna array front-end as signal
option(ENABLE_ZMQ "Enable GNU Radio ZeroMQ Messaging, requires gr-zeromq" ON)
option(ENABLE_ION "Enable ION GNSS-SDR Metadata Standard signal source" OFF)
# Performance analysis tools
option(ENABLE_GPERFTOOLS "Enable linking to Gperftools libraries (tcmalloc and profiler)" OFF)
@ -3356,6 +3358,60 @@ if(ENABLE_AD9361 OR ENABLE_FMCOMMS2 OR ENABLE_PLUTOSDR)
endif()
################################################################################
# ION GNSS-SDR Metadata Standard https://sdr.ion.org/ (OPTIONAL)
################################################################################
if(CMAKE_VERSION VERSION_LESS 3.14)
set(ENABLE_ION OFF) # FetchContent_MakeAvailable is available from CMake 3.14
endif()
if(ENABLE_ION)
include(FetchContent)
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW)
FetchContent_Declare(
gnss_metadata_standard
GIT_REPOSITORY https://github.com/IonMetadataWorkingGroup/GNSS-Metadata-Standard
GIT_TAG 220d116e10db5e403e21b77a1fa25aa35feda198
SOURCE_DIR ${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${GNSSSDR_BINARY_DIR}/gnss-metadata-standard
BINARY_DIR ${GNSSSDR_BINARY_DIR}/gnss-metadata-standard
)
FetchContent_MakeAvailable(gnss_metadata_standard)
if(NOT TARGET ION::ion)
add_library(ION::ion STATIC IMPORTED)
add_dependencies(ION::ion gnss_metadata_standard)
if(CMAKE_GENERATOR STREQUAL "Xcode")
set_target_properties(ION::ion PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION_DEBUG "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}"
IMPORTED_LOCATION_RELEASE "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Release/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}"
IMPORTED_LOCATION_RELWITHDEBINFO "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}"
IMPORTED_LOCATION_MINSIZEREL "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/MinSizeRel/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}"
INTERFACE_INCLUDE_DIRECTORIES "${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard/source/api/inc"
)
set_property(TARGET ION::ion APPEND PROPERTY
INTERFACE_LINK_LIBRARIES
"$<$<CONFIG:Debug>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:Release>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Release/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Release/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:RelWithDebInfo>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:MinSizeRel>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/MinSizeRel/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/MinSizeRel/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:NoOptWithASM>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:Coverage>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:O2WithASM>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:O3WithASM>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
"$<$<CONFIG:ASAN>:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>"
)
else()
set_target_properties(ION::ion PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}"
INTERFACE_INCLUDE_DIRECTORIES "${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard/source/api/inc"
INTERFACE_LINK_LIBRARIES "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}"
)
endif()
endif()
endif()
#####################################################################
# Check signal sources related to FPGA only.
@ -3669,6 +3725,7 @@ add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source
add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.")
add_feature_info(ENABLE_ARRAY ENABLE_ARRAY "Enables Raw_Array_Signal_Source and Array_Signal_Conditioner for using CTTC's antenna array. Requires gr-dbfcttc.")
add_feature_info(ENABLE_ZMQ ENABLE_ZMQ "Enables ZMQ_Signal_Source for GNU Radio ZeroMQ messages. Requires gr-zeromq.")
add_feature_info(ENABLE_ION ENABLE_ION "Enables ION_GSMS_Signal_Source for the ION Metadata Standard.")
add_feature_info(ENABLE_GPERFTOOLS ENABLE_GPERFTOOLS "Enables performance analysis. Requires Gperftools.")
add_feature_info(ENABLE_GPROF ENABLE_GPROF "Enables performance analysis with 'gprof'.")
add_feature_info(ENABLE_CLANG_TIDY ENABLE_CLANG_TIDY "Runs clang-tidy along with the compiler. Requires Clang.")

View File

@ -41,6 +41,11 @@ All notable changes to GNSS-SDR will be documented in this file.
- `-DENABLE_DMA_PROXY`: Checks if the DMA proxy driver is installed for
controlling the DMA in the FPGA and enables its usage.
- Add the `ION_GSMS_Signal_Source`, which is able to process raw data files
described with the
[ION GNSS Software Defined Receiver Metadata Standard](https://sdr.ion.org/).
It requires the `-DENABLE_ION=ON` building configuration option.
### Improvements in Portability:
- Fix building against google-glog 0.7.x.

View File

@ -103,6 +103,11 @@ if(ENABLE_ZMQ)
list(APPEND OPT_DRIVER_HEADERS zmq_signal_source.h)
endif()
if(ENABLE_ION)
list(APPEND OPT_DRIVER_SOURCES ion_gsms_signal_source.cc)
list(APPEND OPT_DRIVER_HEADERS ion_gsms_signal_source.h)
endif()
set(SIGNAL_SOURCE_ADAPTER_SOURCES
signal_source_base.cc
file_source_base.cc
@ -169,7 +174,7 @@ target_include_directories(signal_source_adapters
${GNSSSDR_SOURCE_DIR}/src/core/interfaces
)
if(ENABLE_FPGA OR ENABLE_AD9361)
if(ENABLE_FPGA OR ENABLE_AD9361 OR ENABLE_ION)
target_link_libraries(signal_source_adapters
PUBLIC
signal_source_libs

View File

@ -0,0 +1,234 @@
/*!
* \file ion_gsms_signal_source.h
* \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ion_gsms_signal_source.h"
#include "gnss_sdr_flags.h"
#include "gnss_sdr_string_literals.h"
#include "gnss_sdr_valve.h"
#include <gnuradio/blocks/copy.h>
#include <cstdlib>
#include <unordered_set>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
using namespace std::string_literals;
std::vector<std::string> parse_comma_list(const std::string& str)
{
std::vector<std::string> list{};
std::size_t prev_comma_at{0};
while (prev_comma_at < str.size())
{
std::size_t comma_at = str.find_first_of(',', prev_comma_at);
if (comma_at == std::string::npos)
{
comma_at = str.size();
}
list.emplace_back(str.substr(prev_comma_at, (comma_at - prev_comma_at)));
prev_comma_at = comma_at + 1;
}
return list;
}
IONGSMSSignalSource::IONGSMSSignalSource(const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_streams,
unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue)
: SignalSourceBase(configuration, role, "ION_GSMS_Signal_Source"s),
stream_ids_(parse_comma_list(configuration->property(role + ".streams"s, ""s))),
metadata_filepath_(configuration->property(role + ".metadata_filename"s, "../data/example_capture_metadata.sdrx"s)),
in_streams_(in_streams),
out_streams_(out_streams)
{
if (in_streams_ > 0)
{
LOG(ERROR) << "A signal source does not have an input stream";
}
if (out_streams_ <= 0)
{
LOG(ERROR) << "A signal source does not have an output stream";
}
// Parse XML metadata file
load_metadata();
// Make source vector
sources_ = make_stream_sources(stream_ids_);
for (const auto& source : sources_)
{
for (std::size_t i = 0; i < source->output_stream_count(); ++i)
{
copy_blocks_.push_back(gr::blocks::copy::make(source->output_stream_item_size(i)));
valves_.push_back(gnss_sdr_make_valve(source->output_stream_item_size(i), source->output_stream_total_sample_count(i), queue));
}
}
}
void IONGSMSSignalSource::load_metadata()
{
try
{
GnssMetadata::XmlProcessor xml_proc;
if (!xml_proc.Load(metadata_filepath_.c_str(), false, metadata_))
{
LOG(WARNING) << "Could not load XML metadata file " << metadata_filepath_;
std::cerr << "Could not load XML metadata file " << metadata_filepath_ << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
}
catch (GnssMetadata::ApiException& e)
{
LOG(WARNING) << "API Exception while loading XML metadata file: " << std::to_string(e.Error());
std::cerr << "Could not load XML metadata file " << metadata_filepath_ << " : " << std::to_string(e.Error()) << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
catch (std::exception& e)
{
LOG(WARNING) << "Exception while loading XML metadata file: " << e.what();
std::cerr << "Could not load XML metadata file " << metadata_filepath_ << " : " << e.what() << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
}
std::vector<IONGSMSFileSource::sptr> IONGSMSSignalSource::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())
{
bool block_done = false;
for (const auto& chunk : block.Chunks())
{
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
bool found = false;
for (const auto& stream_id : stream_ids)
{
if (stream_id == stream.Id())
{
found = true;
break;
}
}
if (found)
{
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
block_done = true;
break;
}
}
if (block_done)
{
break;
}
}
if (block_done)
{
break;
}
}
}
break;
}
}
}
return sources;
}
void IONGSMSSignalSource::connect(gr::top_block_sptr top_block)
{
std::size_t cumulative_index = 0;
for (const auto& source : sources_)
{
for (std::size_t i = 0; i < source->output_stream_count(); ++i, ++cumulative_index)
{
top_block->connect(source, i, copy_blocks_[cumulative_index], 0);
top_block->connect(copy_blocks_[cumulative_index], 0, valves_[cumulative_index], 0);
}
}
}
void IONGSMSSignalSource::disconnect(gr::top_block_sptr top_block)
{
std::size_t cumulative_index = 0;
for (const auto& source : sources_)
{
for (std::size_t i = 0; i < source->output_stream_count(); ++i, ++cumulative_index)
{
top_block->disconnect(source, i, copy_blocks_[cumulative_index], 0);
top_block->disconnect(copy_blocks_[cumulative_index], 0, valves_[cumulative_index], 0);
}
}
}
gr::basic_block_sptr IONGSMSSignalSource::get_left_block()
{
LOG(WARNING) << "Trying to get signal source left block.";
// return gr_basic_block_sptr();
return IONGSMSFileSource::sptr();
}
gr::basic_block_sptr IONGSMSSignalSource::get_right_block()
{
return get_right_block(0);
}
gr::basic_block_sptr IONGSMSSignalSource::get_right_block(int RF_channel)
{
if (RF_channel < 0 || RF_channel >= static_cast<int>(copy_blocks_.size()))
{
LOG(WARNING) << "'RF_channel' out of bounds while trying to get signal source right block.";
return valves_[0];
}
return valves_[RF_channel];
}

View File

@ -0,0 +1,84 @@
/*!
* \file ion_gsms_signal_source.h
* \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H
#define GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H
#include "configuration_interface.h"
#include "file_source_base.h"
#include "gnss_sdr_timestamp.h"
#include "ion_gsms.h"
#include <GnssMetadata.h>
#include <cstdint>
#include <string>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_adapters
* \{ */
/*!
* \brief Class that reads signals samples from a file
* and adapts it to a SignalSourceInterface
*/
class IONGSMSSignalSource : public SignalSourceBase
{
public:
IONGSMSSignalSource(const ConfigurationInterface* configuration, const std::string& role,
unsigned int in_streams, unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue);
~IONGSMSSignalSource() override = default;
protected:
void connect(gr::top_block_sptr top_block) override;
void disconnect(gr::top_block_sptr top_block) override;
gr::basic_block_sptr get_left_block() override;
gr::basic_block_sptr get_right_block() override;
gr::basic_block_sptr get_right_block(int RF_channel) override;
inline size_t item_size() override
{
return (*sources_.begin())->output_stream_item_size(0);
}
private:
std::vector<IONGSMSFileSource::sptr> make_stream_sources(const std::vector<std::string>& stream_ids) const;
void load_metadata();
std::vector<std::string> stream_ids_;
std::vector<IONGSMSFileSource::sptr> sources_;
std::vector<gnss_shared_ptr<gr::block>> copy_blocks_;
std::vector<gnss_shared_ptr<gr::block>> valves_;
std::string metadata_filepath_;
GnssMetadata::Metadata metadata_;
gnss_shared_ptr<Gnss_Sdr_Timestamp> timestamp_block_;
std::string timestamp_file_;
uint32_t in_streams_;
uint32_t out_streams_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H

View File

@ -21,6 +21,11 @@ if(ENABLE_PLUTOSDR)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_iio_source.h)
endif()
if(ENABLE_ION)
set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ion_gsms.cc)
set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ion_gsms.h)
endif()
set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES
fifo_reader.cc
unpack_byte_2bit_samples.cc

View File

@ -0,0 +1,204 @@
/*!
* \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-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ion_gsms.h"
#include "gnuradio/block.h"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
#else
#include <absl/log/log.h>
#endif
IONGSMSFileSource::IONGSMSFileSource(
const fs::path& metadata_filepath,
const GnssMetadata::File& file,
const GnssMetadata::Block& block,
const std::vector<std::string>& stream_ids)
: gr::sync_block(
"ion_gsms_file_source",
gr::io_signature::make(0, 0, 0),
make_output_signature(block, stream_ids)),
file_stream_(metadata_filepath.parent_path() / file.Url().Value(), std::ios::in | std::ios::binary),
io_buffer_offset_(0),
maximum_item_rate_(0),
chunk_cycle_length_(0)
{
fs::path data_filepath = metadata_filepath.parent_path() / file.Url().Value();
std::size_t block_offset = file.Offset();
if (!file_stream_.is_open())
{
LOG(WARNING) << "ION_GSMS_Signal_Source - Unable to open the samples file: " << (data_filepath).c_str();
std::cerr << "ION_GSMS_Signal_Source - Unable to open the samples file: " << (data_filepath).c_str() << std::endl;
std::cout << "GNSS-SDR program ended.\n";
exit(1);
}
// Skip offset and block header
file_stream_.seekg(file.Offset() + block_offset + block.SizeHeader());
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));
chunk_cycle_length_ += chunk.CountWords() * chunk.SizeWord();
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_item_rates_.push_back(chunk_data_.back()->output_stream_item_rate(i));
maximum_item_rate_ = std::max(chunk_data_.back()->output_stream_item_rate(i), maximum_item_rate_);
}
}
output_stream_count_ = output_stream_offset;
output_stream_total_sample_counts_.resize(output_stream_count_);
std::size_t cycle_count = block.Cycles();
if (cycle_count == 0)
{
// Read the whole file
const std::size_t file_size = fs::file_size(data_filepath);
cycle_count = std::floor((file_size - block_offset - block.SizeHeader()) / chunk_cycle_length_);
}
for (std::size_t i = 0; i < output_stream_count_; ++i)
{
output_stream_total_sample_counts_[i] = cycle_count * output_stream_item_rates_[i];
}
}
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];
}
std::size_t IONGSMSFileSource::output_stream_total_sample_count(std::size_t stream_index) const
{
return output_stream_total_sample_counts_[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<int> item_sizes{};
for (const auto& chunk : block.Chunks())
{
for (const auto& lump : chunk.Lumps())
{
for (const auto& stream : lump.Streams())
{
bool found = false;
for (const auto& stream_id : stream_ids)
{
if (stream_id == stream.Id())
{
found = true;
break;
}
}
if (found)
{
++nstreams;
std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor();
if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization())
{
// Samples have 'Complex' format
sample_bitsize /= 2;
}
item_sizes.push_back(bits_to_item_size(sample_bitsize));
}
}
}
}
return gr::io_signature::makev(
nstreams,
nstreams,
item_sizes);
}
int IONGSMSFileSource::work(
int noutput_items,
gr_vector_const_void_star& input_items __attribute__((unused)),
gr_vector_void_star& output_items)
{
// Compute the maximum number of samples that will be copied across all output buffer.
// If there are more than one output buffer (multichannel set up), the one with the most samples will be used as the maximum.
//
// Complex samples produce 2 items each (I and Q). In order to account for them, we subtract 1 from `noutput_items` and
// then floor the division. During testing, not doing this caused `max_sample_output` to oscillate between two values, thus
// resizing the `io_buffer_` on each call to `work()`.
const std::size_t max_sample_output = std::floor((noutput_items - 1.0) / maximum_item_rate_);
// Resize the IO buffer to fit exactly the maximum amount of samples that will be outputted.
io_buffer_.resize(max_sample_output * chunk_cycle_length_);
// We will be walking the IO buffer with this variable.
io_buffer_offset_ = 0;
// Read samples from file into IO buffer
const std::size_t bytes_to_read = io_buffer_.size();
file_stream_.read(io_buffer_.data(), bytes_to_read);
// Reset `items_produced_` vector. This vector will accumulate the amount of items produced for each output stream.
items_produced_.clear();
items_produced_.resize(output_items.size());
// Walk the IO buffer one chunk cycle at a time. See ION documentation for a definition of chunk and chunk cycle.
while (io_buffer_offset_ < bytes_to_read)
{
// Iterate chunks within a chunk cycle
for (auto& c : chunk_data_)
{
auto* chunk = c.get();
// Copy chunk into a separate buffer where the samples will be shifted from.
const std::size_t bytes_copied = chunk->read_from_buffer(reinterpret_cast<uint8_t*>(io_buffer_.data()), io_buffer_offset_);
// Advance IO buffer offset
io_buffer_offset_ += bytes_copied;
// Shift samples into output buffers following the appropriate unpacking strategy for this chunk.
chunk->write_to_output(output_items, items_produced_);
}
}
// Call `produce(int, int)` with the appropriate item count for each output stream.
for (std::size_t i = 0; i < items_produced_.size(); ++i)
{
produce(i, items_produced_[i]);
}
return WORK_CALLED_PRODUCE;
}

View File

@ -0,0 +1,74 @@
/*!
* \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-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_ION_GSMS_H
#define GNSS_SDR_ION_GSMS_H
#include "gnss_block_interface.h"
#include "gnss_sdr_filesystem.h"
#include "ion_gsms_chunk_data.h"
#include <gnuradio/block.h>
#include <gnuradio/sync_block.h>
#include <cstddef>
#include <fstream>
#include <memory>
#include <string>
#include <vector>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_gnuradio_blocks
* \{ */
class IONGSMSFileSource : public gr::sync_block
{
public:
using sptr = gnss_shared_ptr<IONGSMSFileSource>;
IONGSMSFileSource(
const fs::path& metadata_filepath,
const GnssMetadata::File& file,
const GnssMetadata::Block& block,
const std::vector<std::string>& stream_ids);
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;
std::size_t output_stream_total_sample_count(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);
std::ifstream file_stream_;
std::vector<char> io_buffer_;
std::size_t io_buffer_offset_;
std::vector<int> items_produced_;
std::size_t output_stream_count_;
std::vector<std::size_t> output_stream_item_sizes_;
std::vector<std::size_t> output_stream_item_rates_;
std::vector<std::size_t> output_stream_total_sample_counts_;
std::size_t maximum_item_rate_;
std::vector<std::shared_ptr<IONGSMSChunkData>> chunk_data_;
std::size_t chunk_cycle_length_;
};
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_H

View File

@ -7,6 +7,7 @@
set(OPT_SIGNAL_SOURCE_LIB_SOURCES "")
set(OPT_SIGNAL_SOURCE_LIB_HEADERS "")
if(ENABLE_FMCOMMS2 OR ENABLE_AD9361)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad9361_manager.h)
@ -41,7 +42,14 @@ if(ENABLE_PLUTOSDR)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad936x_iio_custom.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} pps_samplestamp.h)
set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.cc)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ppstcprx.h)
endif()
if(ENABLE_ION)
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_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_stream_encodings.h)
set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_chunk_unpacking_ctx.h)
endif()
@ -130,6 +138,10 @@ if(ENABLE_FPGA OR ENABLE_AD9361)
)
endif()
if(ENABLE_ION)
target_link_libraries(signal_source_libs PUBLIC ION::ion algorithms_libs)
endif()
if(ENABLE_CLANG_TIDY)
if(CLANG_TIDY_EXE)
set_target_properties(signal_source_libs

View File

@ -0,0 +1,271 @@
/*!
* \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-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "ion_gsms_chunk_data.h"
#include <cstring>
#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())
{
// Instantiate the Allocator functor
Allocator allocator(countwords_, buffer_);
// Call with_word_type with the Allocator functor
with_word_type(sizeword_, allocator);
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();
bool found = false;
for (const auto& stream_id : stream_ids)
{
if (stream_id == stream.Id())
{
found = true;
break;
}
}
if (found)
{
streams_.emplace_back(lump, stream, GnssMetadata::encoding_from_string(stream.Encoding()), output_streams + output_stream_offset);
++output_streams;
std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor();
std::size_t sample_rate = stream.RateFactor();
if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization())
{
// Samples have 'Complex' format
sample_bitsize /= 2;
sample_rate *= 2;
}
output_stream_item_size_.push_back(bits_to_item_size(sample_bitsize));
output_stream_item_rate_.push_back(sample_rate);
}
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()
{
Deleter deleter(static_cast<void*>(buffer_));
with_word_type(sizeword_, deleter);
}
std::size_t IONGSMSChunkData::read_from_buffer(uint8_t* buffer, std::size_t offset)
{
memset(buffer_, 0, sizeword_ * countwords_);
memcpy(buffer_, &buffer[offset], sizeword_ * countwords_);
return sizeword_ * countwords_;
}
void IONGSMSChunkData::write_to_output(gr_vector_void_star& outputs, std::vector<int>& output_items)
{
switch (sizeword_)
{
case 1:
unpack_words<int8_t>(outputs, output_items);
break;
case 2:
unpack_words<int16_t>(outputs, output_items);
break;
case 4:
unpack_words<int32_t>(outputs, output_items);
break;
case 8:
unpack_words<int64_t>(outputs, output_items);
break;
default:
LOG(ERROR) << "Unknown word size (" << std::to_string(sizeword_) << "), unpacking nothing.";
break;
}
}
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];
}
std::size_t IONGSMSChunkData::output_stream_item_rate(std::size_t stream_index) const
{
return output_stream_item_rate_[stream_index];
}
template <typename WT>
void IONGSMSChunkData::unpack_words(gr_vector_void_star& outputs, std::vector<int>& output_items)
{
WT* data = static_cast<WT*>(buffer_);
// TODO - Swap endiannes if needed
IONGSMSChunkUnpackingCtx<WT> ctx{
chunk_.Shift(),
data,
countwords_,
};
// Head padding
if (padding_bitsize_ > 0 && chunk_.Padding() == GnssMetadata::Chunk::Head)
{
ctx.shift_padding(padding_bitsize_);
}
// Samples
for (const auto& [lump, stream, encoding, output_index] : streams_)
{
if (output_index == -1)
{
// skip stream
ctx.shift_padding(stream.Packedbits());
}
else
{
output_items[output_index] += write_stream_samples(ctx, lump, stream, encoding, &outputs[output_index]);
}
}
}
template <typename WT>
std::size_t IONGSMSChunkData::write_stream_samples(
IONGSMSChunkUnpackingCtx<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, reinterpret_cast<int8_t**>(out));
}
else if (sample_bitsize <= 16)
{
write_n_samples<WT, int16_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast<int16_t**>(out));
}
else if (sample_bitsize <= 32)
{
write_n_samples<WT, int32_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast<int32_t**>(out));
}
else if (sample_bitsize <= 64)
{
write_n_samples<WT, int64_t>(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast<int64_t**>(out));
}
return sample_count;
}
template <typename WT, typename OT>
void IONGSMSChunkData::write_n_samples(
IONGSMSChunkUnpackingCtx<WT>& ctx,
GnssMetadata::Lump::LumpShift lump_shift,
uint8_t sample_bitsize,
std::size_t sample_count,
GnssMetadata::StreamEncoding stream_encoding,
OT** 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)
{
*sample = 0;
ctx.shift_sample(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)
{
*sample = 0;
ctx.shift_sample(sample_bitsize, sample);
decode_sample(sample_bitsize, sample, stream_encoding);
++sample;
}
}
(*out) += sample_count;
}
// Static utilities
template <typename Sample>
void IONGSMSChunkData::decode_sample(const uint8_t sample_bitsize, Sample* sample, const GnssMetadata::StreamEncoding encoding)
{
// using SampleType = std::remove_pointer_t<decltype(sample)>;
switch (sample_bitsize)
{
case 2:
*sample = GnssMetadata::two_bit_look_up<Sample>[encoding][*sample];
break;
case 3:
*sample = GnssMetadata::three_bit_look_up<Sample>[encoding][*sample];
break;
case 4:
*sample = GnssMetadata::four_bit_look_up<Sample>[encoding][*sample];
break;
case 5:
*sample = GnssMetadata::five_bit_look_up<Sample>[encoding][*sample];
break;
default:
// TODO - Is this an error that can happen?
// for now we'll just do nothing, if the sample is this wide it may need no decoding
break;
}
}

View File

@ -0,0 +1,188 @@
/*!
* \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-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_ION_GSMS_CHUNK_DATA_H
#define GNSS_SDR_ION_GSMS_CHUNK_DATA_H
#include "ion_gsms_chunk_unpacking_ctx.h"
#include "ion_gsms_stream_encodings.h"
#include <gnuradio/block.h>
#include <GnssMetadata.h>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
inline std::size_t bits_to_item_size(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
std::cerr << "Item size too large (" << std::to_string(bit_count) << "), returning nonsense.\n";
return 1;
}
// Define a functor that has a templated operator()
struct Allocator
{
size_t countwords_;
void*& buffer_; // Using void* to hold any type of pointer
Allocator(size_t countwords, void*& buffer)
: countwords_(countwords), buffer_(buffer) {}
template <typename WordType>
void operator()() const
{
buffer_ = new WordType[countwords_];
}
};
// Define a functor to delete the allocated memory
struct Deleter
{
void* buffer_;
explicit Deleter(void* buffer)
: buffer_(buffer) {}
template <typename WordType>
void operator()() const
{
delete[] static_cast<WordType*>(buffer_);
}
};
template <typename Callback>
void with_word_type(uint8_t word_size, Callback 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:
std::cerr << "Unknown word size (" << std::to_string(word_size) << "), returning nonsense.\n";
break;
}
}
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;
std::size_t read_from_buffer(uint8_t* buffer, std::size_t offset);
void write_to_output(gr_vector_void_star& outputs, std::vector<int>& output_items);
std::size_t output_stream_count() const;
std::size_t output_stream_item_size(std::size_t stream_index) const;
std::size_t output_stream_item_rate(std::size_t stream_index) const;
private:
template <typename WT>
void unpack_words(gr_vector_void_star& outputs, std::vector<int>& output_items);
template <typename WT>
std::size_t write_stream_samples(
IONGSMSChunkUnpackingCtx<WT>& ctx,
const GnssMetadata::Lump& lump,
const GnssMetadata::IonStream& stream,
GnssMetadata::StreamEncoding stream_encoding,
void** out);
template <typename WT, typename OT>
void write_n_samples(
IONGSMSChunkUnpackingCtx<WT>& ctx,
GnssMetadata::Lump::LumpShift lump_shift,
uint8_t sample_bitsize,
std::size_t sample_count,
GnssMetadata::StreamEncoding stream_encoding,
OT** out);
template <typename Sample>
static void decode_sample(uint8_t sample_bitsize, Sample* sample, GnssMetadata::StreamEncoding encoding);
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_;
std::vector<std::size_t> output_stream_item_rate_;
struct stream_metadata_t
{
const GnssMetadata::Lump& lump;
const GnssMetadata::IonStream& stream;
GnssMetadata::StreamEncoding stream_encoding;
int output_index = -1;
stream_metadata_t(
const GnssMetadata::Lump& lump_,
const GnssMetadata::IonStream& stream_,
GnssMetadata::StreamEncoding stream_encoding_,
int output_index_ = -1) : lump(lump_),
stream(stream_),
stream_encoding(stream_encoding_),
output_index(output_index_)
{
}
};
std::vector<stream_metadata_t> streams_;
void* buffer_;
};
#endif // GNSS_SDR_ION_GSMS_CHUNK_DATA_H

View File

@ -0,0 +1,184 @@
/*!
* \file ion_gsms_chunk_unpacking_ctx.h
* \brief Holds state and provides utilities for unpacking samples from a chunk
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* This is a template class, and thus, its member functions must be defined in the header file.
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H
#define GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H
#include <gnuradio/block.h>
#include <GnssMetadata.h>
#include <cstdint>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
template <typename WT>
struct IONGSMSChunkUnpackingCtx
{
static constexpr uint8_t word_bitsize_ = sizeof(WT) * 8;
const GnssMetadata::Chunk::WordShift word_shift_direction_;
WT* iterator_ = nullptr; // Not owned by this class, MUST NOT destroy
WT current_word_{};
uint8_t bitshift_ = 0;
IONGSMSChunkUnpackingCtx(
const GnssMetadata::Chunk::WordShift word_shift,
WT* data_buffer,
uint8_t data_buffer_word_count) : word_shift_direction_(word_shift)
{
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
iterator_ = data_buffer;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
iterator_ = &data_buffer[data_buffer_word_count];
}
if (iterator_)
{
advance_word(); // Initializes current_word_
}
}
void advance_word()
{
WT word = *iterator_;
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
++iterator_;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
--iterator_;
}
current_word_ = word;
}
void shift_current_word(uint8_t n)
{
if ((n % word_bitsize_) == 0)
{
for (uint8_t i = 0; i < (n / word_bitsize_); ++i)
{
advance_word();
}
return;
}
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
current_word_ <<= n;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
current_word_ >>= n;
}
bitshift_ += n;
if (bitshift_ >= word_bitsize_)
{
advance_word();
bitshift_ -= word_bitsize_;
}
}
void shift_padding(uint8_t n_bits)
{
if (n_bits == 0)
{
return;
}
if ((n_bits + (bitshift_ % word_bitsize_)) >= word_bitsize_)
{
const uint8_t bits_shifted = word_bitsize_ - (bitshift_ % word_bitsize_);
shift_current_word(bits_shifted);
shift_padding(n_bits - bits_shifted);
}
else
{
shift_current_word(n_bits);
}
}
template <typename OT>
void shift_sample(uint8_t sample_bitsize, OT* output, uint8_t output_bit_offset = 0)
{
if (sample_bitsize % word_bitsize_ == 0)
{
const uint8_t words_per_sample = sample_bitsize / word_bitsize_;
for (uint8_t i = 0; i < words_per_sample; ++i)
{
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
*output |= (current_word_ << ((words_per_sample - 1 - i) * word_bitsize_));
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
*output |= (current_word_ << (i * word_bitsize_));
// TODO - reverse bit order of sample? maybe?
}
advance_word();
}
}
else if ((sample_bitsize + (bitshift_ % word_bitsize_)) > word_bitsize_)
{
const uint8_t bits_shifted = word_bitsize_ - (bitshift_ % word_bitsize_);
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
WT mask = ~((1 << (word_bitsize_ - bits_shifted)) - 1);
*output |= ((current_word_ & mask) >> output_bit_offset);
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
WT mask = ((1 << (bits_shifted)) - 1);
*output |= (current_word_ & mask) << output_bit_offset;
// TODO - reverse bit order of sample? maybe?
}
shift_current_word(bits_shifted);
shift_sample(sample_bitsize - bits_shifted, output, bits_shifted);
}
else
{
if (word_shift_direction_ == GnssMetadata::Chunk::Left)
{
WT mask = ~((1 << (word_bitsize_ - sample_bitsize)) - 1);
OT sample = (current_word_ & mask) >> (word_bitsize_ - sample_bitsize);
*output |= (sample) >> output_bit_offset;
}
else if (word_shift_direction_ == GnssMetadata::Chunk::Right)
{
WT mask = ((1 << (sample_bitsize)) - 1);
*output |= (current_word_ & mask) << output_bit_offset;
// TODO - reverse bit order of sample? maybe?
}
shift_current_word(sample_bitsize);
}
}
};
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H

View File

@ -0,0 +1,170 @@
/*!
* \file ion_gsms_stream_encodings.h
* \brief Implements look up tables for all encodings in the standard
* \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com
*
* These tables are taken from the stardard's official document.
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H
#define GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H
#include <string>
/** \addtogroup Signal_Source
* \{ */
/** \addtogroup Signal_Source_libs
* \{ */
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;
} // namespace StreamEncodings
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]
{-2, -1, 0, 1}, // [1 /*OB*/]
{0, 1, 0, -1}, // [2 /*SM*/]
{0, 0, 1, -1}, // [3 /*MS*/]
{0, 1, -2, -1}, // [4 /*TC*/]
{-2, -1, 1, 0}, // [5 /*OG*/]
{-3, -1, 1, 3}, // [6 /*OBA*/]
{1, 3, -1, -3}, // [7 /*SMA*/]
{1, -1, 3, -3}, // [8 /*MSA*/]
{1, 3, -3, -1}, // [9 /*TCA*/]
{-3, -1, 3, 1}, // [10 /*OGA*/]
};
template <typename T>
inline T three_bit_look_up[11][8]{
{}, // [0]
{-4, -3, -2, -1, 0, 1, 2, 3}, // [1 /*OB*/]
{0, 1, 2, 3, 0, -1, -2, -3}, // [2 /*SM*/]
{0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/]
{0, 1, 2, 3, -4, -3, -2, -1}, // [4 /*TC*/]
{-4, -3, -1, -2, 3, 2, 0, 1}, // [5 /*OG*/]
{-7, -5, -3, -1, 1, 3, 5, 7}, // [6 /*OBA*/]
{1, 3, 5, 7, -1, -3, -5, -7}, // [7 /*SMA*/]
{1, -1, 3, -3, 5, -5, 7, -7}, // [8 /*MSA*/]
{1, 3, 5, 7, -7, -5, -3, -1}, // [9 /*TCA*/]
{-7, -5, -1, -3, 7, 5, 1, 3}, // [10 /*OGA*/]
};
template <typename T>
inline T four_bit_look_up[11][16]{
{}, // [0]
{-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}, // [1 /*OB*/]
{0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7}, // [2 /*SM*/]
{0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/]
{0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}, // [4 /*TC*/]
{-8, -7, -5, -6, -1, -2, -4, -3, 7, 6, 4, 5, 0, 1, 3, 2}, // [5 /*OG*/]
{-15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15}, // [6 /*OBA*/]
{1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15}, // [7 /*SMA*/]
{1, -1, 3, -3, 5, -5, 7, -7, 9, -9, 11, -11, 13, -13, 15, -15}, // [8 /*MSA*/]
{1, 3, 5, 7, 9, 11, 13, 15, -15, -13, -11, -9, -7, -5, -3, -1}, // [9 /*TCA*/]
{-15, -13, -9, -11, -1, -3, -7, -5, 15, 13, 9, 11, 1, 3, 7, 5}, // [10 /*OGA*/]
};
template <typename T>
inline T five_bit_look_up[11][32]{
{}, // [0]
{-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}, // [1 /*OB*/]
{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}, // [2 /*SM*/]
{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}, // [3 /*MS*/]
{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}, // [4 /*TC*/]
{-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}, // [5 /*OG*/]
{-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}, // [6 /*OBA*/]
{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}, // [7 /*SMA*/]
{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}, // [8 /*MSA*/]
{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}, // [9 /*TCA*/]
{-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}, // [10 /*OGA*/]
};
} // namespace GnssMetadata
/** \} */
/** \} */
#endif // GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H

View File

@ -70,6 +70,10 @@ if(ENABLE_FPGA)
target_compile_definitions(core_receiver PUBLIC -DENABLE_FPGA=1)
endif()
if(ENABLE_ION)
target_compile_definitions(core_receiver PRIVATE -DENABLE_ION_SOURCE=1)
endif()
if(GNURADIO_USES_STD_POINTERS)
target_compile_definitions(core_receiver PUBLIC -DGNURADIO_USES_STD_POINTERS=1)
endif()

View File

@ -196,6 +196,11 @@
#include "gps_l1_ca_dll_pll_tracking_gpu.h"
#endif
#if ENABLE_ION_SOURCE
#undef Owner
#include "ion_gsms_signal_source.h"
#endif
using namespace std::string_literals;
namespace
@ -759,7 +764,14 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
block = std::move(block_);
}
#endif
#if ENABLE_ION_SOURCE
else if (implementation == "ION_GSMS_Signal_Source")
{
std::unique_ptr<GNSSBlockInterface> block_ = std::make_unique<IONGSMSSignalSource>(configuration, role, in_streams,
out_streams, queue);
block = std::move(block_);
}
#endif
#if RAW_ARRAY_DRIVER
else if (implementation == "Raw_Array_Signal_Source")
{