diff --git a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc index a777328e4..22a43202b 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.cc @@ -23,6 +23,7 @@ #include "gnss_sdr_filesystem.h" #include "gnss_sdr_make_unique.h" // for std::make_unique in C++11 #include +#include #include #if HAS_BOOST_ENDIAN @@ -146,7 +147,8 @@ void read_file_register_to_local_endian(std::ifstream &binary_input_file, uint64 #endif } -bool are_equal_ignore_nonpositive(std::initializer_list values) +template > +bool are_equal_ignore_nonpositive(const T &values) { std::vector positives; for (const auto &v : values) @@ -198,6 +200,10 @@ labsat23_source::labsat23_source( d_header_parsed(false), d_ls3w_digital_io_enabled(digital_io_enabled) { + d_channel_state_a.identifier = "A"; + d_channel_state_b.identifier = "B"; + d_channel_state_c.identifier = "C"; + d_signal_file_basename = std::string(signal_file_basename); std::string signal_file; this->set_output_multiple(8); @@ -239,53 +245,59 @@ labsat23_source::labsat23_source( this->set_output_multiple(d_number_sample_per_output); const auto size = fs::file_size(d_signal_file_basename); - const auto samples = (size * CHAR_BIT) / d_ls3w_SFT; - const auto samples_to_skip = static_cast(seconds_to_skip * d_ls3w_SMP); - const auto samples_to_read = static_cast(samples - samples_to_skip); + const auto bits = size * CHAR_BIT; - std::cout << ", which contains " << samples << " samples (" << size << " bytes)\n"; + double bw_factor = 0; - if (samples_to_read < 0) + for (const auto &channel_map_it : d_channel_map) { - std::cout << "File duration is smaller then the seconds to skip!\n"; - exit(1); + const auto &channel = channel_map_it.second; + + if (channel.buff_size > 0) + { + bw_factor += 1.0 / channel.bw_div; + } } - const auto signal_duration_s = static_cast(samples_to_read) / d_ls3w_SMP; + const auto bits_per_sample = d_ls3w_QUA * 2; // I and Q + const auto samples = bits / bits_per_sample; + const auto signal_duration_s = bits / (bits_per_sample * bw_factor * d_ls3w_SMP); + std::cout << ", which contains " << samples << " samples (" << size << " bytes)\n"; + std::cout << "GNSS signal recorded time to be processed: " << (signal_duration_s - seconds_to_skip) << " [s]\n"; - std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]\n"; - - if (samples_to_skip > 0) + if (seconds_to_skip > 0) { - LOG(INFO) << "Skipping " << samples_to_skip << " samples of the input file"; - - // We assume all buffers have same size and take advantage of integer rounding - const auto bytes_to_skip = (samples_to_skip * d_ls3w_SFT) / CHAR_BIT; - const auto bytes_to_skip_per_channel = bytes_to_skip / d_ls3w_CHN; - const auto nb_of_channel_buffer_to_skip = bytes_to_skip_per_channel / d_ls4_BUFF_SIZE; - const auto bytes_to_seek_per_channel = nb_of_channel_buffer_to_skip * d_ls4_BUFF_SIZE; - const auto bytes_to_seek = bytes_to_seek_per_channel * d_ls3w_CHN; - const auto bytes_to_read_per_channel = bytes_to_skip_per_channel - bytes_to_seek_per_channel; - - // Advance in the file by a multiple of buffers, then read one buffer of each channel - if (!binary_input_file.seekg(bytes_to_seek, std::ios::beg) || !read_ls4_data()) + if (signal_duration_s < seconds_to_skip) { - LOG(ERROR) << "Error skipping bytes!"; + std::cout << "File duration is smaller then the seconds to skip!\n"; exit(1); } - // Advances the indices to start at the correct index in the buffer we just read - if (d_ls4_BUFF_SIZE_A > 0) + LOG(INFO) << "Skipping " << seconds_to_skip << " seconds of the input file"; + + int64_t total_bytes_to_seek = 0; + + for (const auto &channel_map_it : d_channel_map) { - d_data_index_a += (bytes_to_read_per_channel / sizeof(uint64_t)); + auto &channel = channel_map_it.second; + + if (channel.buff_size > 0) + { + const auto samples_to_skip = static_cast(seconds_to_skip * (static_cast(d_ls3w_SMP) / channel.bw_div)); + const auto bytes_to_skip = (samples_to_skip * bits_per_sample) / CHAR_BIT; + const auto buffers_to_skip = bytes_to_skip / channel.buff_size; + const auto bytes_to_seek = buffers_to_skip * channel.buff_size; + const auto bytes_to_read = bytes_to_skip - bytes_to_seek; + total_bytes_to_seek += bytes_to_seek; + channel.data_index = (bytes_to_read / sizeof(uint64_t)); // Can be set before read is called + } } - if (d_ls4_BUFF_SIZE_B > 0) + + // Advance in the file by a multiple of buffers, then read one buffer of each channel + if (!binary_input_file.seekg(total_bytes_to_seek, std::ios::beg) || !read_ls4_data()) { - d_data_index_b += (bytes_to_read_per_channel / sizeof(uint64_t)); - } - if (d_ls4_BUFF_SIZE_C > 0) - { - d_data_index_c += (bytes_to_read_per_channel / sizeof(uint64_t)); + LOG(ERROR) << "Error skipping bytes!"; + exit(1); } } } @@ -758,128 +770,146 @@ int labsat23_source::read_ls3w_ini(const std::string &filename) { std::stringstream ls4_bw_max_ss(ls4_bw_max); ls4_bw_max_ss >> d_ls4_BW_MAX; - std::cout << "LabSat max bandwidth : " << d_ls4_BW_MAX << "Hz.\n"; + std::cout << "LabSat max bandwidth : " << d_ls4_BW_MAX << " Hz.\n"; + } + + for (const auto &channel_map_it : d_channel_map) + { + auto &channel = channel_map_it.second; + const auto bw_div_str = ini_reader->Get("config", "BW_DIV_" + channel.identifier, empty_string); + + if (!bw_div_str.empty()) + { + std::stringstream bw_div_ss(bw_div_str); + bw_div_ss >> channel.bw_div; + std::cout << "LabSat bandwidth div " << channel.identifier << " : " << channel.bw_div << ".\n"; + } } } } - const auto channel_handler = [this, &ini_reader, &empty_string](const std::string &channel_char, int32_t &cf, int32_t &bw, int32_t &buffer_size, std::vector &buffer) { - const auto channel_name = "channel " + channel_char; - - if (ini_reader->HasSection(channel_name)) - { - const auto cf_str = ini_reader->Get(channel_name, "CF" + channel_char, empty_string); - if (!cf_str.empty()) - { - std::stringstream cf_ss(cf_str); - cf_ss >> cf; - std::cout << "LabSat center frequency for RF " << channel_name << ": " << cf << " Hz\n"; - } - - const auto bw_str = ini_reader->Get(channel_name, "BW" + channel_char, empty_string); - if (!bw_str.empty()) - { - std::stringstream bw_ss(bw_str); - bw_ss >> bw; - std::cout << "LabSat RF filter bandwidth for RF " << channel_name << ": " << bw << " Hz\n"; - } - - if (d_is_ls4) - { - const auto buffer_size_str = ini_reader->Get(channel_name, "BUF_SIZE_" + channel_char, empty_string); - if (!buffer_size_str.empty()) - { - std::stringstream buff_size_ss(buffer_size_str); - buff_size_ss >> buffer_size; - - if (buffer_size > 0) - { - d_ls4_BUFF_SIZE = buffer_size; - - if (buffer_size % sizeof(uint64_t) != 0) - { - std::cerr << "\nConfiguration error: RF " << channel_name << " is BUFF SIZE is not a multiple of " << sizeof(uint64_t) << ".\n"; - std::cerr << "Exiting the program.\n"; - return false; - } - - buffer.resize(buffer_size / sizeof(uint64_t)); - } - std::cout << "LabSat RF BUFFER SIZE for RF " << channel_name << ": " << buffer_size << " bytes\n"; - } - } - } - return true; - }; - - if (!channel_handler("A", d_ls3w_CFA, d_ls3w_BWA, d_ls4_BUFF_SIZE_A, d_ls4_data_a) || - !channel_handler("B", d_ls3w_CFB, d_ls3w_BWB, d_ls4_BUFF_SIZE_B, d_ls4_data_b) || - !channel_handler("C", d_ls3w_CFC, d_ls3w_BWC, d_ls4_BUFF_SIZE_C, d_ls4_data_c)) + for (const auto &channel_map_it : d_channel_map) { - return -1; + auto &channel = channel_map_it.second; + const auto channel_name = "channel " + channel.identifier; + + if (ini_reader->HasSection(channel_name)) + { + const auto cf_str = ini_reader->Get(channel_name, "CF" + channel.identifier, empty_string); + if (!cf_str.empty()) + { + std::stringstream cf_ss(cf_str); + cf_ss >> channel.center_freq; + std::cout << "LabSat center frequency for RF " << channel_name << ": " << channel.center_freq << " Hz\n"; + } + + const auto bw_str = ini_reader->Get(channel_name, "BW" + channel.identifier, empty_string); + if (!bw_str.empty()) + { + std::stringstream bw_ss(bw_str); + bw_ss >> channel.bandwidth; + std::cout << "LabSat RF filter bandwidth for RF " << channel_name << ": " << channel.bandwidth << " Hz\n"; + } + + if (d_is_ls4) + { + const auto buffer_size_str = ini_reader->Get(channel_name, "BUF_SIZE_" + channel.identifier, empty_string); + if (!buffer_size_str.empty()) + { + std::stringstream buff_size_ss(buffer_size_str); + buff_size_ss >> channel.buff_size; + + if (channel.buff_size > 0) + { + if (channel.buff_size % sizeof(uint64_t) != 0) + { + std::cerr << "\nConfiguration error: RF " << channel_name << " is BUFF SIZE is not a multiple of " << sizeof(uint64_t) << ".\n"; + std::cerr << "Exiting the program.\n"; + return -1; + } + + channel.data.resize(channel.buff_size / sizeof(uint64_t)); + } + std::cout << "LabSat RF BUFFER SIZE for RF " << channel_name << ": " << channel.buff_size << " bytes\n"; + } + } + } } if (d_is_ls4) { - if (!are_equal_ignore_nonpositive({d_ls4_BW_MAX, d_ls3w_BWA, d_ls3w_BWB, d_ls3w_BWC})) + d_number_register_per_output = d_ls3w_QUA == 12 ? 3 : 1; + d_number_sample_per_output = (d_number_register_per_output * 64) / (d_ls3w_QUA * 2); + + const auto expected_max_bandwidth_a = d_channel_state_a.bandwidth * d_channel_state_a.bw_div + d_ls4_BW_MAX % d_channel_state_a.bw_div; + const auto expected_max_bandwidth_b = d_channel_state_b.bandwidth * d_channel_state_b.bw_div + d_ls4_BW_MAX % d_channel_state_b.bw_div; + const auto expected_max_bandwidth_c = d_channel_state_c.bandwidth * d_channel_state_c.bw_div + d_ls4_BW_MAX % d_channel_state_c.bw_div; + + if (!are_equal_ignore_nonpositive({d_ls4_BW_MAX, expected_max_bandwidth_a, expected_max_bandwidth_b, expected_max_bandwidth_c})) { - std::cerr << "\nConfiguration error: Currently does not support channels with different bandwidths or different from max bandwidth for LS4 files.\n"; + std::cerr << "\nConfiguration error: Bandwidth configuration is invalid.\n"; std::cerr << "Exiting the program.\n"; return -1; } - if (!are_equal_ignore_nonpositive({d_ls4_BUFF_SIZE_A, d_ls4_BUFF_SIZE_B, d_ls4_BUFF_SIZE_C})) + if (!are_equal_ignore_nonpositive({d_channel_state_a.buff_size * d_channel_state_a.bw_div, d_channel_state_b.buff_size * d_channel_state_b.bw_div, d_channel_state_c.buff_size * d_channel_state_c.bw_div})) { - std::cerr << "\nConfiguration error: Currently does not support channels with different buffer sizes for LS4 files.\n"; + std::cerr << "\nConfiguration error: Buffer size configuration is invalid.\n"; std::cerr << "Exiting the program.\n"; return -1; } + + std::vector selected_bw_divs; + selected_bw_divs.reserve(d_channel_selector_config.size()); + + for (const auto channel_id : d_channel_selector_config) + { + selected_bw_divs.push_back(d_channel_map.at(channel_id).bw_div); + } + + if (!are_equal_ignore_nonpositive(selected_bw_divs)) + { + if (d_channel_selector_config.size() > 1) + { + std::cerr << "\nConfiguration error: Selecting multiple channels with different bandwidths is not supported.\n"; + std::cerr << "Exiting the program.\n"; + return -1; + } + } + + const auto selected_bw_div = static_cast(selected_bw_divs[0]); + + for (const auto &channel_map_it : d_channel_map) + { + auto &channel = channel_map_it.second; + + if (channel.buff_size > 0) + { + // This ensures we increment the indices correctly when all channels do not have the same bandwidth + channel.number_sample_per_output = d_number_register_per_output * (selected_bw_div / channel.bw_div); + } + } } - std::cout << "LabSat selected channel" << ((d_channel_selector_config.size() > 1) ? "s" : "") << ": "; - if (std::find(d_channel_selector_config.begin(), d_channel_selector_config.end(), 1) != d_channel_selector_config.end()) + const std::set channel_selector_config_set(d_channel_selector_config.begin(), d_channel_selector_config.end()); + const std::vector unique_channel_selector_config(channel_selector_config_set.begin(), channel_selector_config_set.end()); + const auto channel_count = static_cast(unique_channel_selector_config.size()); + std::cout << "LabSat selected channel" << ((channel_count > 1) ? "s" : "") << ": "; + + for (int i = 0; i < channel_count; ++i) { - std::cout << "A"; - } - if (std::find(d_channel_selector_config.begin(), d_channel_selector_config.end(), 2) != d_channel_selector_config.end()) - { - if (d_ls3w_CHN > 1) + const auto channel_id = unique_channel_selector_config.at(i); + const auto &channel_char = d_channel_map.at(channel_id).identifier; + + if (channel_id > channel_count) { - if (d_channel_selector_config.size() == 1) - { - std::cout << "B"; - } - else - { - std::cout << ", B"; - } - } - else - { - std::cerr << "\nConfiguration error: RF channel B is selected but not found in data file.\n"; - std::cerr << "Exiting the program.\n"; - return -1; - } - } - if (std::find(d_channel_selector_config.begin(), d_channel_selector_config.end(), 3) != d_channel_selector_config.end()) - { - if (d_ls3w_CHN > 2) - { - if (d_channel_selector_config.size() == 1) - { - std::cout << "C"; - } - else - { - std::cout << ", C"; - } - } - else - { - std::cerr << "\nConfiguration error: RF channel C is selected but not found in data file.\n"; + std::cerr << "\nConfiguration error: RF channel " << channel_char << " is selected but not found in data file.\n"; std::cerr << "Exiting the program.\n"; return -1; } + + std::cout << channel_char << (i + 1 < channel_count ? ", " : ""); } + std::cout << '\n'; d_ls3w_samples_per_register = this->number_of_samples_per_ls3w_register(); @@ -1173,7 +1203,7 @@ int labsat23_source::parse_ls4_data(int noutput_items, std::vector for (int j = 0; j < registers_to_read; j++) { - if ((d_data_index_a + d_data_index_b + d_data_index_c) >= d_read_index) + if ((d_channel_state_a.data_index + d_channel_state_b.data_index + d_channel_state_c.data_index) >= d_read_index) { if (!read_ls4_data()) { @@ -1186,34 +1216,19 @@ int labsat23_source::parse_ls4_data(int noutput_items, std::vector for (size_t channel_index = 0; channel_index < d_channel_selector_config.size(); ++channel_index) { gr_complex *aux = out[channel_index]; - - switch (d_channel_selector_config[channel_index]) - { - case 1: - write_samples_ls4(d_data_index_a, output_index, d_number_sample_per_output, d_ls3w_QUA, d_ls4_data_a, aux); - break; - case 2: - write_samples_ls4(d_data_index_b, output_index, d_number_sample_per_output, d_ls3w_QUA, d_ls4_data_b, aux); - break; - case 3: - write_samples_ls4(d_data_index_c, output_index, d_number_sample_per_output, d_ls3w_QUA, d_ls4_data_c, aux); - break; - } + auto &channel = d_channel_map.at(d_channel_selector_config[channel_index]); + write_samples_ls4(channel.data_index, output_index, d_number_sample_per_output, d_ls3w_QUA, channel.data, aux); } output_index += d_number_sample_per_output; - if (d_ls4_BUFF_SIZE_A > 0) + for (const auto &channel_map_it : d_channel_map) { - d_data_index_a += d_number_register_per_output; - } - if (d_ls4_BUFF_SIZE_B > 0) - { - d_data_index_b += d_number_register_per_output; - } - if (d_ls4_BUFF_SIZE_C > 0) - { - d_data_index_c += d_number_register_per_output; + auto &channel = channel_map_it.second; + if (channel.buff_size > 0) + { + channel.data_index += channel.number_sample_per_output; + } } } @@ -1230,22 +1245,22 @@ int labsat23_source::parse_ls4_data(int noutput_items, std::vector bool labsat23_source::read_ls4_data() { - const auto read_file = [this](int size, std::vector &data) { - if (size > 0) - { - binary_input_file.read(reinterpret_cast(data.data()), size); - d_read_index += data.size(); - if (binary_input_file.gcount() != size) - { - return false; - } - } - return true; - }; + for (const auto &channel_map_it : d_channel_map) + { + auto &channel = channel_map_it.second; - return read_file(d_ls4_BUFF_SIZE_A, d_ls4_data_a) && - read_file(d_ls4_BUFF_SIZE_B, d_ls4_data_b) && - read_file(d_ls4_BUFF_SIZE_C, d_ls4_data_c); + if (channel.buff_size > 0) + { + binary_input_file.read(reinterpret_cast(channel.data.data()), channel.buff_size); + d_read_index += channel.data.size(); + if (binary_input_file.gcount() != channel.buff_size) + { + return false; + } + } + } + + return true; } diff --git a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h index 435cb1d0d..d74ab22e7 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/labsat23_source.h @@ -105,12 +105,6 @@ private: int32_t d_ls3w_QUA{}; int32_t d_ls3w_CHN{}; int32_t d_ls3w_SFT{}; - int32_t d_ls3w_CFA{}; - int32_t d_ls3w_CFB{}; - int32_t d_ls3w_CFC{}; - int32_t d_ls3w_BWA{}; - int32_t d_ls3w_BWB{}; - int32_t d_ls3w_BWC{}; int d_ls3w_spare_bits{}; int d_ls3w_samples_per_register{}; bool d_is_ls3w = false; @@ -118,24 +112,28 @@ private: bool d_ls3w_digital_io_enabled = false; // Data members for Labsat 4 + int32_t d_ls4_BW_MAX{0}; int32_t d_number_sample_per_output{0}; int32_t d_number_register_per_output{0}; uint64_t d_read_index{0}; - uint64_t d_data_index_a{0}; - uint64_t d_data_index_b{0}; - uint64_t d_data_index_c{0}; + struct ChannelState + { + std::string identifier; + int32_t center_freq{0}; + int32_t bandwidth{0}; + int32_t bw_div{0}; + int32_t buff_size{0}; + int32_t number_sample_per_output{0}; + uint64_t data_index{0}; + std::vector data; + }; - int32_t d_ls4_BW_MAX{0}; + ChannelState d_channel_state_a; + ChannelState d_channel_state_b; + ChannelState d_channel_state_c; - int32_t d_ls4_BUFF_SIZE_A{0}; - int32_t d_ls4_BUFF_SIZE_B{0}; - int32_t d_ls4_BUFF_SIZE_C{0}; - int32_t d_ls4_BUFF_SIZE{0}; - - std::vector d_ls4_data_a; - std::vector d_ls4_data_b; - std::vector d_ls4_data_c; + std::map d_channel_map{{1, d_channel_state_a}, {2, d_channel_state_b}, {3, d_channel_state_c}}; };