From 6d743708608a514cbc64f452b989effb7b5a02b9 Mon Sep 17 00:00:00 2001 From: Javier Arribas Date: Mon, 27 Aug 2018 18:05:19 +0200 Subject: [PATCH] Joining Galileo FNAV and FNAV telemetry decoders in a single GNURadio block --- .../adapters/galileo_e1b_telemetry_decoder.cc | 2 +- .../adapters/galileo_e1b_telemetry_decoder.h | 5 +- .../adapters/galileo_e5a_telemetry_decoder.cc | 2 +- .../adapters/galileo_e5a_telemetry_decoder.h | 5 +- .../gnuradio_blocks/CMakeLists.txt | 3 +- .../galileo_e1b_telemetry_decoder_cc.cc | 501 ----------- .../galileo_e5a_telemetry_decoder_cc.cc | 513 ------------ .../galileo_e5a_telemetry_decoder_cc.h | 127 --- .../galileo_telemetry_decoder_cc.cc | 780 ++++++++++++++++++ ...er_cc.h => galileo_telemetry_decoder_cc.h} | 58 +- .../gnuradio_blocks/dll_pll_veml_tracking.cc | 9 +- src/core/system_parameters/Galileo_E1.h | 6 +- 12 files changed, 828 insertions(+), 1183 deletions(-) delete mode 100644 src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.cc delete mode 100644 src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.cc delete mode 100644 src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.h create mode 100644 src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.cc rename src/algorithms/telemetry_decoder/gnuradio_blocks/{galileo_e1b_telemetry_decoder_cc.h => galileo_telemetry_decoder_cc.h} (62%) diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc index ab20cab1d..f7a663358 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.cc @@ -55,7 +55,7 @@ GalileoE1BTelemetryDecoder::GalileoE1BTelemetryDecoder(ConfigurationInterface* c dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); // make telemetry decoder object - telemetry_decoder_ = galileo_e1b_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me + telemetry_decoder_ = galileo_make_telemetry_decoder_cc(satellite_, 1, dump_); //unified galileo decoder set to INAV (frame_type=1) DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; channel_ = 0; if (in_streams_ > 1) diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h index d762eabd8..119e294ad 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e1b_telemetry_decoder.h @@ -36,7 +36,7 @@ #include "telemetry_decoder_interface.h" -#include "galileo_e1b_telemetry_decoder_cc.h" +#include "galileo_telemetry_decoder_cc.h" #include "gnss_satellite.h" #include @@ -76,7 +76,6 @@ public: void set_satellite(const Gnss_Satellite& satellite) override; inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } - inline void reset() override { return; @@ -88,7 +87,7 @@ public: } private: - galileo_e1b_telemetry_decoder_cc_sptr telemetry_decoder_; + galileo_telemetry_decoder_cc_sptr telemetry_decoder_; Gnss_Satellite satellite_; int channel_; bool dump_; diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc index 48ed8b216..99ab590ea 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.cc @@ -58,7 +58,7 @@ GalileoE5aTelemetryDecoder::GalileoE5aTelemetryDecoder(ConfigurationInterface* c dump_ = configuration->property(role + ".dump", false); dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); // make telemetry decoder object - telemetry_decoder_ = galileo_e5a_make_telemetry_decoder_cc(satellite_, dump_); // TODO fix me + telemetry_decoder_ = galileo_make_telemetry_decoder_cc(satellite_, 2, dump_); //unified galileo decoder set to FNAV (frame_type=2) DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")"; channel_ = 0; if (in_streams_ > 1) diff --git a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h index 4a4167bf5..022636384 100644 --- a/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h +++ b/src/algorithms/telemetry_decoder/adapters/galileo_e5a_telemetry_decoder.h @@ -37,7 +37,7 @@ #ifndef GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_H_ #define GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_H_ -#include "galileo_e5a_telemetry_decoder_cc.h" +#include "galileo_telemetry_decoder_cc.h" #include "telemetry_decoder_interface.h" #include @@ -76,7 +76,6 @@ public: void set_satellite(const Gnss_Satellite& satellite) override; inline void set_channel(int channel) override { telemetry_decoder_->set_channel(channel); } - inline void reset() override { return; @@ -88,7 +87,7 @@ public: } private: - galileo_e5a_telemetry_decoder_cc_sptr telemetry_decoder_; + galileo_telemetry_decoder_cc_sptr telemetry_decoder_; Gnss_Satellite satellite_; int channel_; bool dump_; diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt b/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt index 3af26e46b..5a49bf03a 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/CMakeLists.txt @@ -20,11 +20,10 @@ set(TELEMETRY_DECODER_GR_BLOCKS_SOURCES gps_l1_ca_telemetry_decoder_cc.cc gps_l2c_telemetry_decoder_cc.cc gps_l5_telemetry_decoder_cc.cc - galileo_e1b_telemetry_decoder_cc.cc sbas_l1_telemetry_decoder_cc.cc - galileo_e5a_telemetry_decoder_cc.cc glonass_l1_ca_telemetry_decoder_cc.cc glonass_l2_ca_telemetry_decoder_cc.cc + galileo_telemetry_decoder_cc.cc ) include_directories( diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.cc deleted file mode 100644 index 769902600..000000000 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.cc +++ /dev/null @@ -1,501 +0,0 @@ -/*! - * \file galileo_e1b_telemetry_decoder_cc.cc - * \brief Implementation of a Galileo INAV message demodulator block - * \author Mara Branzanti 2013. mara.branzanti(at)gmail.com - * \author Javier Arribas 2013. jarribas(at)cttc.es - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - - -#include "galileo_e1b_telemetry_decoder_cc.h" -#include "control_message_factory.h" -#include "convolutional.h" -#include "gnss_synchro.h" -#include -#include -#include -#include -#include - - -#define CRC_ERROR_LIMIT 6 - -using google::LogMessage; - - -galileo_e1b_telemetry_decoder_cc_sptr -galileo_e1b_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) -{ - return galileo_e1b_telemetry_decoder_cc_sptr(new galileo_e1b_telemetry_decoder_cc(satellite, dump)); -} - - -void galileo_e1b_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits) -{ - Viterbi(page_part_bits, out0, state0, out1, state1, - page_part_symbols, KK, nn, DataLength); -} - - -void galileo_e1b_telemetry_decoder_cc::deinterleaver(int32_t rows, int32_t cols, double *in, double *out) -{ - for (int32_t r = 0; r < rows; r++) - { - for (int32_t c = 0; c < cols; c++) - { - out[c * rows + r] = in[r * cols + c]; - } - } -} - - -galileo_e1b_telemetry_decoder_cc::galileo_e1b_telemetry_decoder_cc( - const Gnss_Satellite &satellite, - bool dump) : gr::block("galileo_e1b_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Ephemeris data port out - this->message_port_register_out(pmt::mp("telemetry")); - // initialize internal vars - d_dump = dump; - d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - LOG(INFO) << "Initializing GALILEO E1B TELEMETRY PROCESSING"; - d_samples_per_symbol = (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS) / Galileo_E1_B_SYMBOL_RATE_BPS; - - // set the preamble - uint16_t preambles_bits[GALILEO_INAV_PREAMBLE_LENGTH_BITS] = GALILEO_INAV_PREAMBLE; - - d_symbols_per_preamble = GALILEO_INAV_PREAMBLE_LENGTH_BITS * d_samples_per_symbol; - - memcpy(static_cast(this->d_preambles_bits), static_cast(preambles_bits), GALILEO_INAV_PREAMBLE_LENGTH_BITS * sizeof(uint16_t)); - - // preamble bits to sampled symbols - d_preambles_symbols = static_cast(volk_gnsssdr_malloc(d_symbols_per_preamble * sizeof(int32_t), volk_gnsssdr_get_alignment())); - int32_t n = 0; - for (int32_t i = 0; i < GALILEO_INAV_PREAMBLE_LENGTH_BITS; i++) - { - for (uint32_t j = 0; j < d_samples_per_symbol; j++) - { - if (d_preambles_bits[i] == 1) - { - d_preambles_symbols[n] = 1; - } - else - { - d_preambles_symbols[n] = -1; - } - n++; - } - } - d_sample_counter = 0ULL; - d_stat = 0; - d_preamble_index = 0ULL; - - d_flag_frame_sync = false; - - d_flag_parity = false; - d_TOW_at_current_symbol_ms = 0; - d_TOW_at_Preamble_ms = 0; - delta_t = 0; - d_CRC_error_counter = 0; - flag_even_word_arrived = 0; - d_flag_preamble = false; - d_channel = 0; - flag_TOW_set = false; - - // vars for Viterbi decoder - int32_t max_states = 1 << mm; // 2^mm - g_encoder[0] = 121; // Polynomial G1 - g_encoder[1] = 91; // Polynomial G2 - out0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - out1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - state0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - state1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - // create appropriate transition matrices - nsc_transit(out0, state0, 0, g_encoder, KK, nn); - nsc_transit(out1, state1, 1, g_encoder, KK, nn); -} - - -galileo_e1b_telemetry_decoder_cc::~galileo_e1b_telemetry_decoder_cc() -{ - volk_gnsssdr_free(d_preambles_symbols); - volk_gnsssdr_free(out0); - volk_gnsssdr_free(out1); - volk_gnsssdr_free(state0); - volk_gnsssdr_free(state1); - if (d_dump_file.is_open() == true) - { - try - { - d_dump_file.close(); - } - catch (const std::exception &ex) - { - LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); - } - } -} - - -void galileo_e1b_telemetry_decoder_cc::decode_word(double *page_part_symbols, int32_t frame_length) -{ - // 1. De-interleave - double *page_part_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); - deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_deint); - - // 2. Viterbi decoder - // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) - // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180º - for (int32_t i = 0; i < frame_length; i++) - { - if ((i + 1) % 2 == 0) - { - page_part_symbols_deint[i] = -page_part_symbols_deint[i]; - } - } - - int32_t *page_part_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); - viterbi_decoder(page_part_symbols_deint, page_part_bits); - volk_gnsssdr_free(page_part_symbols_deint); - - // 3. Call the Galileo page decoder - std::string page_String; - for (int32_t i = 0; i < (frame_length / 2); i++) - { - if (page_part_bits[i] > 0) - { - page_String.push_back('1'); - } - else - { - page_String.push_back('0'); - } - } - - if (page_part_bits[0] == 1) - { - // DECODE COMPLETE WORD (even + odd) and TEST CRC - d_nav.split_page(page_String, flag_even_word_arrived); - if (d_nav.flag_CRC_test == true) - { - LOG(INFO) << "Galileo E1 CRC correct in channel " << d_channel << " from satellite " << d_satellite; - //std::cout << "Galileo E1 CRC correct on channel " << d_channel << " from satellite " << d_satellite << std::endl; - } - else - { - std::cout << "Galileo E1 CRC error in channel " << d_channel << " from satellite " << d_satellite << std::endl; - LOG(INFO) << "Galileo E1 CRC error in channel " << d_channel << " from satellite " << d_satellite; - } - flag_even_word_arrived = 0; - } - else - { - // STORE HALF WORD (even page) - d_nav.split_page(page_String.c_str(), flag_even_word_arrived); - flag_even_word_arrived = 1; - } - volk_gnsssdr_free(page_part_bits); - - // 4. Push the new navigation data to the queues - if (d_nav.have_new_ephemeris() == true) - { - // get object for this SV (mandatory) - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_ephemeris()); - std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_iono_and_GST() == true) - { - // get object for this SV (mandatory) - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_iono()); - std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_utc_model() == true) - { - // get object for this SV (mandatory) - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_utc_model()); - std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_almanac() == true) - { - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_almanac()); - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - //debug - std::cout << "Galileo E1 I/NAV almanac received in channel " << d_channel << " from satellite " << d_satellite << std::endl; - DLOG(INFO) << "GPS_to_Galileo time conversion:"; - DLOG(INFO) << "A0G=" << tmp_obj->A_0G_10; - DLOG(INFO) << "A1G=" << tmp_obj->A_1G_10; - DLOG(INFO) << "T0G=" << tmp_obj->t_0G_10; - DLOG(INFO) << "WN_0G_10=" << tmp_obj->WN_0G_10; - DLOG(INFO) << "Current parameters:"; - DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms; - DLOG(INFO) << "d_nav.WN_0=" << d_nav.WN_0; - delta_t = tmp_obj->A_0G_10 + tmp_obj->A_1G_10 * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G_10 + 604800 * (fmod((d_nav.WN_0 - tmp_obj->WN_0G_10), 64))); - DLOG(INFO) << "delta_t=" << delta_t << "[s]"; - } -} - - -void galileo_e1b_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) -{ - d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; - DLOG(INFO) << "Navigation Satellite set to " << d_satellite; -} - - -void galileo_e1b_telemetry_decoder_cc::set_channel(int32_t channel) -{ - d_channel = channel; - LOG(INFO) << "Navigation channel set to " << channel; - // ############# ENABLE DATA FILE LOG ################# - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_filename = "telemetry"; - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } - } - } -} - - -int galileo_e1b_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - int32_t corr_value = 0; - int32_t preamble_diff = 0; - - Gnss_Synchro **out = reinterpret_cast(&output_items[0]); // Get the output buffer pointer - const Gnss_Synchro **in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer - - Gnss_Synchro current_symbol; // structure to save the synchronization information and send the output object to the next block - // 1. Copy the current tracking output - current_symbol = in[0][0]; - d_symbol_history.push_back(current_symbol); // add new symbol to the symbol queue - d_sample_counter++; // count for the processed samples - consume_each(1); - - d_flag_preamble = false; - uint32_t required_symbols = static_cast(GALILEO_INAV_PAGE_SYMBOLS) + static_cast(d_symbols_per_preamble); - - if (d_symbol_history.size() > required_symbols) - { - // TODO Optimize me! - // ******* preamble correlation ******** - for (int32_t i = 0; i < d_symbols_per_preamble; i++) - { - if (d_symbol_history.at(i).Prompt_I < 0) // symbols clipping - { - corr_value -= d_preambles_symbols[i]; - } - else - { - corr_value += d_preambles_symbols[i]; - } - } - } - - // ******* frame sync ****************** - if (d_stat == 0) // no preamble information - { - if (abs(corr_value) >= d_symbols_per_preamble) - { - d_preamble_index = d_sample_counter; // record the preamble sample stamp - LOG(INFO) << "Preamble detection for Galileo satellite " << this->d_satellite; - d_stat = 1; // enter into frame pre-detection status - } - } - else if (d_stat == 1) // possible preamble lock - { - if (abs(corr_value) >= d_symbols_per_preamble) - { - // check preamble separation - preamble_diff = static_cast(d_sample_counter - d_preamble_index); - if (abs(preamble_diff - GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS) == 0) - { - // try to decode frame - LOG(INFO) << "Starting page decoder for Galileo satellite " << this->d_satellite; - d_preamble_index = d_sample_counter; // record the preamble sample stamp - d_stat = 2; - } - else - { - if (preamble_diff > GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS) - { - d_stat = 0; // start again - } - } - } - } - else if (d_stat == 2) - { - if (d_sample_counter == d_preamble_index + static_cast(GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS)) - { - // NEW Galileo page part is received - // 0. fetch the symbols into an array - int32_t frame_length = GALILEO_INAV_PAGE_PART_SYMBOLS - d_symbols_per_preamble; - double *page_part_symbols = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); - - for (int32_t i = 0; i < frame_length; i++) - { - if (corr_value > 0) - { - page_part_symbols[i] = d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! - } - else - { - page_part_symbols[i] = -d_symbol_history.at(i + d_symbols_per_preamble).Prompt_I; // because last symbol of the preamble is just received now! - } - } - - // call the decoder - decode_word(page_part_symbols, frame_length); - if (d_nav.flag_CRC_test == true) - { - d_CRC_error_counter = 0; - d_flag_preamble = true; // valid preamble indicator (initialized to false every work()) - d_preamble_index = d_sample_counter; // record the preamble sample stamp (t_P) - if (!d_flag_frame_sync) - { - d_flag_frame_sync = true; - DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " - << d_symbol_history.at(0).Tracking_sample_counter << " [samples]"; - } - } - else - { - d_CRC_error_counter++; - d_preamble_index = d_sample_counter; // record the preamble sample stamp - if (d_CRC_error_counter > CRC_ERROR_LIMIT) - { - LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; - d_flag_frame_sync = false; - d_stat = 0; - d_TOW_at_current_symbol_ms = 0; - d_TOW_at_Preamble_ms = 0; - d_nav.flag_TOW_set = false; - } - } - volk_gnsssdr_free(page_part_symbols); - } - } - - // UPDATE GNSS SYNCHRO DATA - // 2. Add the telemetry decoder information - if (this->d_flag_preamble == true and d_nav.flag_TOW_set == true) - // update TOW at the preamble instant - { - if (d_nav.flag_TOW_5 == true) // page 5 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) - { - // TOW_5 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later plus the decoding delay - d_TOW_at_Preamble_ms = static_cast(d_nav.TOW_5 * 1000.0); - d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast(GALILEO_INAV_PAGE_PART_MS + (required_symbols + 1) * GALILEO_E1_CODE_PERIOD_MS); - d_nav.flag_TOW_5 = false; - } - - else if (d_nav.flag_TOW_6 == true) // page 6 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) - { - // TOW_6 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later plus the decoding delay - d_TOW_at_Preamble_ms = static_cast(d_nav.TOW_6 * 1000.0); - d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast(GALILEO_INAV_PAGE_PART_MS + (required_symbols + 1) * GALILEO_E1_CODE_PERIOD_MS); - d_nav.flag_TOW_6 = false; - } - else - { - // this page has no timing information - d_TOW_at_current_symbol_ms += static_cast(GALILEO_E1_CODE_PERIOD_MS); // + GALILEO_INAV_PAGE_PART_SYMBOLS*GALILEO_E1_CODE_PERIOD; - } - } - else // if there is not a new preamble, we define the TOW of the current symbol - { - if (d_nav.flag_TOW_set == true) - { - d_TOW_at_current_symbol_ms += static_cast(GALILEO_E1_CODE_PERIOD_MS); - } - } - - // remove used symbols from history - // todo: Use circular buffer here - if (d_symbol_history.size() > required_symbols) - { - d_symbol_history.pop_front(); - } - - if (d_nav.flag_TOW_set) - { - if (d_nav.flag_GGTO_1 == true and d_nav.flag_GGTO_2 == true and d_nav.flag_GGTO_3 == true and d_nav.flag_GGTO_4 == true) // all GGTO parameters arrived - { - delta_t = d_nav.A_0G_10 + d_nav.A_1G_10 * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - d_nav.t_0G_10 + 604800.0 * (fmod((d_nav.WN_0 - d_nav.WN_0G_10), 64.0))); - } - - current_symbol.Flag_valid_word = d_nav.flag_TOW_set; - current_symbol.TOW_at_current_symbol_ms = d_TOW_at_current_symbol_ms; - // todo: Galileo to GPS time conversion should be moved to observable block. - // current_symbol.TOW_at_current_symbol_ms -= delta_t; //Galileo to GPS TOW - - if (d_dump == true) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - uint64_t tmp_ulong_int; - tmp_double = static_cast(d_TOW_at_current_symbol_ms) / 1000.0; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_ulong_int = current_symbol.Tracking_sample_counter; - d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); - tmp_double = static_cast(d_TOW_at_Preamble_ms) / 1000.0; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception writing observables dump file " << e.what(); - } - } - // 3. Make the output (copy the object contents to the GNURadio reserved memory) - *out[0] = current_symbol; - return 1; - } - else - { - return 0; - } -} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.cc deleted file mode 100644 index b033627e7..000000000 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.cc +++ /dev/null @@ -1,513 +0,0 @@ -/*! - * \file galileo_e5a_telemetry_decoder_cc.cc - * \brief Implementation of a Galileo FNAV message demodulator block - * \author Marc Sales, 2014. marcsales92(at)gmail.com - * Javier Arribas, 2017. jarribas(at)cttc.es - * \based on work from: - *
    - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
- * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#include "galileo_e5a_telemetry_decoder_cc.h" -#include "control_message_factory.h" -#include "convolutional.h" -#include "display.h" -#include -#include -#include -#include -#include -#include - - -#define GALILEO_E5a_CRC_ERROR_LIMIT 6 - -using google::LogMessage; - - -galileo_e5a_telemetry_decoder_cc_sptr -galileo_e5a_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump) -{ - return galileo_e5a_telemetry_decoder_cc_sptr(new galileo_e5a_telemetry_decoder_cc(satellite, dump)); -} - - -void galileo_e5a_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits) -{ - Viterbi(page_part_bits, out0, state0, out1, state1, - page_part_symbols, KK, nn, DataLength); -} - - -void galileo_e5a_telemetry_decoder_cc::deinterleaver(int32_t rows, int32_t cols, double *in, double *out) -{ - for (int32_t r = 0; r < rows; r++) - { - for (int32_t c = 0; c < cols; c++) - { - out[c * rows + r] = in[r * cols + c]; - } - } -} - - -void galileo_e5a_telemetry_decoder_cc::decode_word(double *page_symbols, int32_t frame_length) -{ - // 1. De-interleave - double *page_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); - deinterleaver(GALILEO_FNAV_INTERLEAVER_ROWS, GALILEO_FNAV_INTERLEAVER_COLS, page_symbols, page_symbols_deint); - - // 2. Viterbi decoder - // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) - // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180� - for (int32_t i = 0; i < frame_length; i++) - { - if ((i + 1) % 2 == 0) - { - page_symbols_deint[i] = -page_symbols_deint[i]; - } - } - int32_t *page_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); - viterbi_decoder(page_symbols_deint, page_bits); - volk_gnsssdr_free(page_symbols_deint); - - // 3. Call the Galileo page decoder - std::string page_String; - for (int32_t i = 0; i < frame_length; i++) - { - if (page_bits[i] > 0) - { - page_String.push_back('1'); - } - else - { - page_String.push_back('0'); - } - } - volk_gnsssdr_free(page_bits); - - // DECODE COMPLETE WORD (even + odd) and TEST CRC - d_nav.split_page(page_String); - if (d_nav.flag_CRC_test == true) - { - LOG(INFO) << "Galileo E5a CRC correct in channel " << d_channel << " from satellite " << d_satellite; - } - else - { - std::cout << "Galileo E5a CRC error in channel " << d_channel << " from satellite " << d_satellite << std::endl; - LOG(INFO) << "Galileo E5a CRC error in channel " << d_channel << " from satellite " << d_satellite; - } - - // 4. Push the new navigation data to the queues - if (d_nav.have_new_ephemeris() == true) - { - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_ephemeris()); - std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_iono_and_GST() == true) - { - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_iono()); - std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } - if (d_nav.have_new_utc_model() == true) - { - std::shared_ptr tmp_obj = std::make_shared(d_nav.get_utc_model()); - std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; - this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); - } -} - - -galileo_e5a_telemetry_decoder_cc::galileo_e5a_telemetry_decoder_cc( - const Gnss_Satellite &satellite, bool dump) : gr::block("galileo_e5a_telemetry_decoder_cc", - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), - gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) -{ - // Ephemeris data port out - this->message_port_register_out(pmt::mp("telemetry")); - // initialize internal vars - d_dump = dump; - d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - - // set the preamble - for (int32_t i = 0; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - { - if (GALILEO_FNAV_PREAMBLE.at(i) == '0') - { - d_preambles_bits[i] = 1; - } - else - { - d_preambles_bits[i] = -1; - } - } - for (int32_t i = 0; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - { - for (int32_t k = 0; k < GALILEO_FNAV_CODES_PER_SYMBOL; k++) - { - d_preamble_samples[(i * GALILEO_FNAV_CODES_PER_SYMBOL) + k] = d_preambles_bits[i]; - } - } - - d_sample_counter = 0ULL; - d_stat = 0; - corr_value = 0; - d_flag_preamble = false; - d_preamble_index = 0ULL; - d_flag_frame_sync = false; - d_TOW_at_current_symbol_ms = 0; - d_TOW_at_Preamble_ms = 0; - flag_TOW_set = false; - d_CRC_error_counter = 0; - d_channel = 0; - delta_t = 0.0; - d_symbol_counter = 0; - d_prompt_acum = 0.0; - flag_bit_start = true; - new_symbol = false; - required_symbols = GALILEO_FNAV_SYMBOLS_PER_PAGE + GALILEO_FNAV_PREAMBLE_LENGTH_BITS; - - // vars for Viterbi decoder - int32_t max_states = 1 << mm; // 2^mm - g_encoder[0] = 121; // Polynomial G1 - g_encoder[1] = 91; // Polynomial G2 - out0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - out1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - state0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - state1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); - // create appropriate transition matrices - nsc_transit(out0, state0, 0, g_encoder, KK, nn); - nsc_transit(out1, state1, 1, g_encoder, KK, nn); -} - - -galileo_e5a_telemetry_decoder_cc::~galileo_e5a_telemetry_decoder_cc() -{ - volk_gnsssdr_free(out0); - volk_gnsssdr_free(out1); - volk_gnsssdr_free(state0); - volk_gnsssdr_free(state1); - if (d_dump_file.is_open() == true) - { - try - { - d_dump_file.close(); - } - catch (const std::exception &ex) - { - LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); - } - } -} - - -void galileo_e5a_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) -{ - d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); - DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; - DLOG(INFO) << "Navigation Satellite set to " << d_satellite; -} - - -void galileo_e5a_telemetry_decoder_cc::set_channel(int32_t channel) -{ - d_channel = channel; - LOG(INFO) << "Navigation channel set to " << channel; - // Enable data file logging - if (d_dump == true) - { - if (d_dump_file.is_open() == false) - { - try - { - d_dump_filename = "telemetry"; - d_dump_filename.append(boost::lexical_cast(d_channel)); - d_dump_filename.append(".dat"); - d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); - d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); - LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); - } - } - } -} - - -int galileo_e5a_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - int32_t preamble_diff = 0; - - Gnss_Synchro *out = reinterpret_cast(output_items[0]); // Get the output buffer pointer - const Gnss_Synchro *in = reinterpret_cast(input_items[0]); // Get the input buffer pointer - - // 1. Copy the current tracking output - Gnss_Synchro current_sample = in[0]; - d_symbol_counter++; - if (flag_bit_start) - { - d_prompt_acum += current_sample.Prompt_I; - if (d_symbol_counter == GALILEO_FNAV_CODES_PER_SYMBOL) - { - current_sample.Prompt_I = d_prompt_acum / static_cast(GALILEO_FNAV_CODES_PER_SYMBOL); - d_symbol_history.push_back(current_sample); // add new symbol to the symbol queue - d_prompt_acum = 0.0; - d_symbol_counter = 0; - new_symbol = true; - } - } - else - { - if (current_sample.Prompt_I < 0.0) - { - d_preamble_init.push_back(1); - } - else - { - d_preamble_init.push_back(-1); - } - - if (d_preamble_init.size() == GALILEO_FNAV_CODES_PER_PREAMBLE) - { - std::deque::iterator iter; - int32_t k = 0; - corr_value = 0; - for (iter = d_preamble_init.begin(); iter != d_preamble_init.end(); iter++) - { - corr_value += *iter * d_preamble_samples[k]; - k++; - } - if (abs(corr_value) == GALILEO_FNAV_CODES_PER_PREAMBLE) - { - d_symbol_counter = 0; - flag_bit_start = true; - corr_value = 0; - d_preamble_init.clear(); - d_symbol_history.clear(); - LOG(INFO) << "Bit start sync for Galileo E5a satellite " << d_satellite; - } - else - { - d_preamble_init.pop_front(); - } - } - } - d_sample_counter++; // count for the processed samples - consume_each(1); - - d_flag_preamble = false; - - if ((d_symbol_history.size() > required_symbols) && new_symbol) - { - // ****************** Preamble orrelation ****************** - corr_value = 0; - for (int32_t i = 0; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++) - { - if (d_symbol_history.at(i).Prompt_I < 0.0) // symbols clipping - { - corr_value -= d_preambles_bits[i]; - } - else - { - corr_value += d_preambles_bits[i]; - } - } - } - // ****************** Frame sync ****************** - if ((d_stat == 0) && new_symbol) // no preamble information - { - if (abs(corr_value) == GALILEO_FNAV_PREAMBLE_LENGTH_BITS) - { - d_preamble_index = d_sample_counter; // record the preamble sample stamp - LOG(INFO) << "Preamble detection for Galileo E5a satellite " << d_satellite; - d_stat = 1; // enter into frame pre-detection status - } - } - else if ((d_stat == 1) && new_symbol) // possible preamble lock - { - if (abs(corr_value) == GALILEO_FNAV_PREAMBLE_LENGTH_BITS) - { - // check preamble separation - preamble_diff = static_cast(d_sample_counter - d_preamble_index); - if (preamble_diff == GALILEO_FNAV_CODES_PER_PAGE) - { - // try to decode frame - LOG(INFO) << "Starting page decoder for Galileo E5a satellite " << d_satellite; - d_preamble_index = d_sample_counter; // record the preamble sample stamp - d_stat = 2; - } - else if (preamble_diff > GALILEO_FNAV_CODES_PER_PAGE) - { - d_stat = 0; // start again - flag_bit_start = false; - LOG(INFO) << "Preamble diff = " << preamble_diff; - } - } - } - else if ((d_stat == 2) && new_symbol) - { - if (d_sample_counter == (d_preamble_index + static_cast(GALILEO_FNAV_CODES_PER_PAGE))) - { - // NEW Galileo page part is received - // 0. fetch the symbols into an array - int32_t frame_length = GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS; - double corr_sign = 0.0; - if (corr_value > 0) - { - corr_sign = -1.0; - } - else - { - corr_sign = 1.0; - } - for (int32_t i = 0; i < frame_length; i++) - { - page_symbols[i] = corr_sign * d_symbol_history.at(i + GALILEO_FNAV_PREAMBLE_LENGTH_BITS).Prompt_I; // because last symbol of the preamble is just received now! - } - - // call the decoder - decode_word(page_symbols, frame_length); - if (d_nav.flag_CRC_test == true) - { - d_CRC_error_counter = 0; - d_flag_preamble = true; // valid preamble indicator (initialized to false every work()) - d_preamble_index = d_sample_counter; // record the preamble sample stamp (t_P) - if (!d_flag_frame_sync) - { - d_flag_frame_sync = true; - DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at " - << d_symbol_history.at(0).Tracking_sample_counter << " [samples]"; - } - } - else - { - d_CRC_error_counter++; - d_preamble_index = d_sample_counter; // record the preamble sample stamp - if (d_CRC_error_counter > GALILEO_E5A_CRC_ERROR_LIMIT) - { - LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; - d_flag_frame_sync = false; - d_stat = 0; - flag_bit_start = false; - d_nav.flag_TOW_set = false; - d_TOW_at_current_symbol_ms = 0; - d_TOW_at_Preamble_ms = 0; - } - } - } - } - new_symbol = false; - - // UPDATE GNSS SYNCHRO DATA - // Add the telemetry decoder information - if (d_flag_preamble and d_nav.flag_TOW_set) - // update TOW at the preamble instant - // We expect a preamble each 10 seconds (FNAV page period) - { - if (d_nav.flag_TOW_1 == true) - { - d_TOW_at_Preamble_ms = static_cast(d_nav.FNAV_TOW_1 * 1000.0); - d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); - d_nav.flag_TOW_1 = false; - } - else if (d_nav.flag_TOW_2 == true) - { - d_TOW_at_Preamble_ms = static_cast(d_nav.FNAV_TOW_2 * 1000.0); - d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); - d_nav.flag_TOW_2 = false; - } - else if (d_nav.flag_TOW_3 == true) - { - d_TOW_at_Preamble_ms = static_cast(d_nav.FNAV_TOW_3 * 1000.0); - d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); - d_nav.flag_TOW_3 = false; - } - else if (d_nav.flag_TOW_4 == true) - { - d_TOW_at_Preamble_ms = static_cast(d_nav.FNAV_TOW_4 * 1000.0); - d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); - d_nav.flag_TOW_4 = false; - } - else - { - d_TOW_at_current_symbol_ms += static_cast(GALILEO_E5a_CODE_PERIOD_MS); - } - } - else // if there is not a new preamble, we define the TOW of the current symbol - { - if (d_nav.flag_TOW_set == true) - { - d_TOW_at_current_symbol_ms += static_cast(GALILEO_E5a_CODE_PERIOD_MS); - } - } - - // remove used symbols from history - // todo: Use circular buffer here - while (d_symbol_history.size() > required_symbols) - { - d_symbol_history.pop_front(); - } - - if (d_nav.flag_TOW_set) - { - current_sample.Flag_valid_word = true; - current_sample.TOW_at_current_symbol_ms = d_TOW_at_current_symbol_ms; - if (d_dump) - { - // MULTIPLEXED FILE RECORDING - Record results to file - try - { - double tmp_double; - uint64_t tmp_ulong_int; - tmp_double = static_cast(d_TOW_at_current_symbol_ms) / 1000.0; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - tmp_ulong_int = current_sample.Tracking_sample_counter; - d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); - tmp_double = static_cast(d_TOW_at_Preamble_ms) / 1000.0; - d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); - } - catch (const std::ifstream::failure &e) - { - LOG(WARNING) << "Exception writing Galileo E5a Telemetry Decoder dump file " << e.what(); - } - } - // 3. Make the output - out[0] = current_sample; - return 1; - } - else - { - return 0; - } -} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.h deleted file mode 100644 index 522f5777e..000000000 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e5a_telemetry_decoder_cc.h +++ /dev/null @@ -1,127 +0,0 @@ -/*! - * \file galileo_e5a_telemetry_decoder_cc.cc - * \brief Implementation of a Galileo FNAV message demodulator block - * \author Marc Sales, 2014. marcsales92(at)gmail.com - * Javier Arribas, 2017. jarribas(at)cttc.es - * \based on work from: - *
    - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
- * - * - * ------------------------------------------------------------------------- - * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) - * - * GNSS-SDR is a software defined Global Navigation - * Satellite Systems receiver - * - * This file is part of GNSS-SDR. - * - * GNSS-SDR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GNSS-SDR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNSS-SDR. If not, see . - * - * ------------------------------------------------------------------------- - */ - -#ifndef GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_CC_H_ -#define GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_CC_H_ - -#include "Galileo_E5a.h" -#include "gnss_satellite.h" -#include "galileo_fnav_message.h" -#include "galileo_ephemeris.h" -#include "galileo_almanac.h" -#include "galileo_iono.h" -#include "galileo_utc_model.h" -#include "gnss_synchro.h" -#include -#include -#include -#include - - -class galileo_e5a_telemetry_decoder_cc; - -typedef boost::shared_ptr galileo_e5a_telemetry_decoder_cc_sptr; - -galileo_e5a_telemetry_decoder_cc_sptr galileo_e5a_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); - - -/*! - * \brief This class implements a block that decodes the FNAV data defined in Galileo ICD - * - */ -class galileo_e5a_telemetry_decoder_cc : public gr::block -{ -public: - ~galileo_e5a_telemetry_decoder_cc(); - void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN - void set_channel(int32_t channel); //!< Set receiver's channel - /*! - * \brief This is where all signal processing takes place - */ - int general_work(int noutput_items, gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - -private: - friend galileo_e5a_telemetry_decoder_cc_sptr - galileo_e5a_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); - galileo_e5a_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); - - void viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits); - - void deinterleaver(int32_t rows, int32_t cols, double *in, double *out); - - void decode_word(double *page_symbols, int32_t frame_length); - - int32_t d_preambles_bits[GALILEO_FNAV_PREAMBLE_LENGTH_BITS]; - int32_t d_preamble_samples[GALILEO_FNAV_CODES_PER_PREAMBLE]; - std::deque d_preamble_init; - int32_t d_stat; - int32_t d_CRC_error_counter; - int32_t d_channel; - int32_t d_symbol_counter; - int32_t corr_value; - uint32_t required_symbols; - uint64_t d_sample_counter; - uint64_t d_preamble_index; - bool d_flag_frame_sync; - bool d_flag_preamble; - bool d_dump; - bool flag_TOW_set; - bool flag_bit_start; - bool new_symbol; - double d_prompt_acum; - double page_symbols[GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS]; - uint32_t d_TOW_at_Preamble_ms; - uint32_t d_TOW_at_current_symbol_ms; - double delta_t; //GPS-GALILEO time offset - std::string d_dump_filename; - std::ofstream d_dump_file; - std::deque d_symbol_history; - Gnss_Satellite d_satellite; - // navigation message vars - Galileo_Fnav_Message d_nav; - - // vars for Viterbi decoder - int32_t *out0, *out1, *state0, *state1; - int32_t g_encoder[2]; - const int32_t nn = 2; // Coding rate 1/n - const int32_t KK = 7; // Constraint Length - int32_t mm = KK - 1; - const int32_t CodeLength = 488; - int32_t DataLength = (CodeLength / nn) - mm; -}; - -#endif /* GNSS_SDR_GALILEO_E5A_TELEMETRY_DECODER_CC_H_ */ diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.cc new file mode 100644 index 000000000..aa53529fe --- /dev/null +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.cc @@ -0,0 +1,780 @@ +/*! + * \file galileo_telemetry_decoder_cc.cc + * \brief Implementation of a Galileo unified INAV and FNAV message demodulator block + * \author Javier Arribas 2018. jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#include "galileo_telemetry_decoder_cc.h" +#include "control_message_factory.h" +#include "convolutional.h" +#include "display.h" +#include "gnss_synchro.h" +#include +#include +#include +#include +#include + + +#define CRC_ERROR_LIMIT 6 + +using google::LogMessage; + + +galileo_telemetry_decoder_cc_sptr +galileo_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump) +{ + return galileo_telemetry_decoder_cc_sptr(new galileo_telemetry_decoder_cc(satellite, frame_type, dump)); +} + + +void galileo_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits) +{ + Viterbi(page_part_bits, out0, state0, out1, state1, + page_part_symbols, KK, nn, DataLength); +} + + +void galileo_telemetry_decoder_cc::deinterleaver(int32_t rows, int32_t cols, double *in, double *out) +{ + for (int32_t r = 0; r < rows; r++) + { + for (int32_t c = 0; c < cols; c++) + { + out[c * rows + r] = in[r * cols + c]; + } + } +} + + +galileo_telemetry_decoder_cc::galileo_telemetry_decoder_cc( + const Gnss_Satellite &satellite, int frame_type, + bool dump) : gr::block("galileo_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)), + gr::io_signature::make(1, 1, sizeof(Gnss_Synchro))) +{ + // Ephemeris data port out + this->message_port_register_out(pmt::mp("telemetry")); + // initialize internal vars + d_dump = dump; + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + d_frame_type = frame_type; + LOG(INFO) << "Initializing GALILEO UNIFIED TELEMETRY DECODER"; + + switch (d_frame_type) + { + case 1: //INAV + { + d_PRN_code_period_ms = static_cast(GALILEO_E1_CODE_PERIOD_MS); + d_samples_per_symbol = Galileo_E1_B_SAMPLES_PER_SYMBOL; + d_bits_per_preamble = GALILEO_INAV_PREAMBLE_LENGTH_BITS; + // set the preamble + d_samples_per_preamble = GALILEO_INAV_PREAMBLE_LENGTH_BITS * d_samples_per_symbol; + d_preamble_period_symbols = GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS; + d_required_symbols = static_cast(GALILEO_INAV_PAGE_SYMBOLS) + d_samples_per_preamble; + // preamble bits to sampled symbols + d_preamble_samples = static_cast(volk_gnsssdr_malloc(d_samples_per_preamble * sizeof(int32_t), volk_gnsssdr_get_alignment())); + d_frame_length_symbols = GALILEO_INAV_PAGE_PART_SYMBOLS - GALILEO_INAV_PREAMBLE_LENGTH_BITS; + CodeLength = GALILEO_INAV_PAGE_PART_SYMBOLS - GALILEO_INAV_PREAMBLE_LENGTH_BITS; + DataLength = (CodeLength / nn) - mm; + break; + } + case 2: //FNAV + { + d_PRN_code_period_ms = static_cast(GALILEO_E5a_CODE_PERIOD_MS); + d_samples_per_symbol = GALILEO_FNAV_CODES_PER_SYMBOL; + d_bits_per_preamble = GALILEO_FNAV_PREAMBLE_LENGTH_BITS; + // set the preamble + d_samples_per_preamble = GALILEO_FNAV_PREAMBLE_LENGTH_BITS * d_samples_per_symbol; + d_preamble_period_symbols = GALILEO_FNAV_CODES_PER_PAGE; + d_required_symbols = static_cast(GALILEO_FNAV_SYMBOLS_PER_PAGE) * d_samples_per_symbol + d_samples_per_preamble; + // preamble bits to sampled symbols + d_preamble_samples = static_cast(volk_gnsssdr_malloc(d_samples_per_preamble * sizeof(int32_t), volk_gnsssdr_get_alignment())); + + d_secondary_code_samples = static_cast(volk_gnsssdr_malloc(Galileo_E5a_I_SECONDARY_CODE_LENGTH * sizeof(int32_t), volk_gnsssdr_get_alignment())); + d_frame_length_symbols = GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS; + CodeLength = GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS; + DataLength = (CodeLength / nn) - mm; + for (int32_t i = 0; i < Galileo_E5a_I_SECONDARY_CODE_LENGTH; i++) + { + if (Galileo_E5a_I_SECONDARY_CODE.at(i) == '1') + { + d_secondary_code_samples[i] = 1; + } + else + { + d_secondary_code_samples[i] = -1; + } + } + break; + } + default: + std::cout << "Galileo unified telemetry decoder error: Unknown frame type " << std::endl; + } + + d_page_part_symbols = static_cast(volk_gnsssdr_malloc(d_frame_length_symbols * sizeof(double), volk_gnsssdr_get_alignment())); + int32_t n = 0; + for (int32_t i = 0; i < d_bits_per_preamble; i++) + { + switch (d_frame_type) + { + case 1: //INAV + { + if (GALILEO_INAV_PREAMBLE.at(i) == '1') + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = 1; + n++; + } + } + else + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = -1; + n++; + } + } + break; + } + case 2: //FNAV for E5a-I + { + // Galileo E5a data channel (E5a-I) still has a secondary code + int m = 0; + if (GALILEO_FNAV_PREAMBLE.at(i) == '1') + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = d_secondary_code_samples[m]; + n++; + m++; + m = m % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + else + { + for (uint32_t j = 0; j < d_samples_per_symbol; j++) + { + d_preamble_samples[n] = -d_secondary_code_samples[m]; + n++; + m++; + m = m % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + break; + } + } + } + d_sample_counter = 0ULL; + d_stat = 0; + d_preamble_index = 0ULL; + + d_flag_frame_sync = false; + + d_flag_parity = false; + d_TOW_at_current_symbol_ms = 0; + d_TOW_at_Preamble_ms = 0; + delta_t = 0; + d_CRC_error_counter = 0; + flag_even_word_arrived = 0; + d_flag_preamble = false; + d_channel = 0; + flag_TOW_set = false; + + // vars for Viterbi decoder + int32_t max_states = 1 << mm; // 2^mm + g_encoder[0] = 121; // Polynomial G1 + g_encoder[1] = 91; // Polynomial G2 + out0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + out1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + state0 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + state1 = static_cast(volk_gnsssdr_malloc(max_states * sizeof(int32_t), volk_gnsssdr_get_alignment())); + // create appropriate transition matrices + nsc_transit(out0, state0, 0, g_encoder, KK, nn); + nsc_transit(out1, state1, 1, g_encoder, KK, nn); +} + + +galileo_telemetry_decoder_cc::~galileo_telemetry_decoder_cc() +{ + volk_gnsssdr_free(d_preamble_samples); + if (d_frame_type == 2) + { + volk_gnsssdr_free(d_secondary_code_samples); + } + volk_gnsssdr_free(d_page_part_symbols); + volk_gnsssdr_free(out0); + volk_gnsssdr_free(out1); + volk_gnsssdr_free(state0); + volk_gnsssdr_free(state1); + if (d_dump_file.is_open() == true) + { + try + { + d_dump_file.close(); + } + catch (const std::exception &ex) + { + LOG(WARNING) << "Exception in destructor closing the dump file " << ex.what(); + } + } +} + + +void galileo_telemetry_decoder_cc::decode_INAV_word(double *page_part_symbols, int32_t frame_length) +{ + // 1. De-interleave + double *page_part_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); + deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_deint); + + // 2. Viterbi decoder + // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) + // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180º + for (int32_t i = 0; i < frame_length; i++) + { + if ((i + 1) % 2 == 0) + { + page_part_symbols_deint[i] = -page_part_symbols_deint[i]; + } + } + + int32_t *page_part_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); + viterbi_decoder(page_part_symbols_deint, page_part_bits); + volk_gnsssdr_free(page_part_symbols_deint); + + // 3. Call the Galileo page decoder + std::string page_String; + for (int32_t i = 0; i < (frame_length / 2); i++) + { + if (page_part_bits[i] > 0) + { + page_String.push_back('1'); + } + else + { + page_String.push_back('0'); + } + } + + if (page_part_bits[0] == 1) + { + // DECODE COMPLETE WORD (even + odd) and TEST CRC + d_inav_nav.split_page(page_String, flag_even_word_arrived); + if (d_inav_nav.flag_CRC_test == true) + { + LOG(INFO) << "Galileo E1 CRC correct in channel " << d_channel << " from satellite " << d_satellite; + } + else + { + LOG(INFO) << "Galileo E1 CRC error in channel " << d_channel << " from satellite " << d_satellite; + } + flag_even_word_arrived = 0; + } + else + { + // STORE HALF WORD (even page) + d_inav_nav.split_page(page_String.c_str(), flag_even_word_arrived); + flag_even_word_arrived = 1; + } + volk_gnsssdr_free(page_part_bits); + + // 4. Push the new navigation data to the queues + if (d_inav_nav.have_new_ephemeris() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_ephemeris()); + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_inav_nav.have_new_iono_and_GST() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_iono()); + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_inav_nav.have_new_utc_model() == true) + { + // get object for this SV (mandatory) + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_utc_model()); + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_inav_nav.have_new_almanac() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_almanac()); + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + //debug + std::cout << "Galileo E1 I/NAV almanac received in channel " << d_channel << " from satellite " << d_satellite << std::endl; + DLOG(INFO) << "GPS_to_Galileo time conversion:"; + DLOG(INFO) << "A0G=" << tmp_obj->A_0G_10; + DLOG(INFO) << "A1G=" << tmp_obj->A_1G_10; + DLOG(INFO) << "T0G=" << tmp_obj->t_0G_10; + DLOG(INFO) << "WN_0G_10=" << tmp_obj->WN_0G_10; + DLOG(INFO) << "Current parameters:"; + DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms; + DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.WN_0; + delta_t = tmp_obj->A_0G_10 + tmp_obj->A_1G_10 * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G_10 + 604800 * (fmod((d_inav_nav.WN_0 - tmp_obj->WN_0G_10), 64))); + DLOG(INFO) << "delta_t=" << delta_t << "[s]"; + } +} + + +void galileo_telemetry_decoder_cc::decode_FNAV_word(double *page_symbols, int32_t frame_length) +{ + // 1. De-interleave + double *page_symbols_deint = static_cast(volk_gnsssdr_malloc(frame_length * sizeof(double), volk_gnsssdr_get_alignment())); + deinterleaver(GALILEO_FNAV_INTERLEAVER_ROWS, GALILEO_FNAV_INTERLEAVER_COLS, page_symbols, page_symbols_deint); + + // 2. Viterbi decoder + // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) + // 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180� + for (int32_t i = 0; i < frame_length; i++) + { + if ((i + 1) % 2 == 0) + { + page_symbols_deint[i] = -page_symbols_deint[i]; + } + } + int32_t *page_bits = static_cast(volk_gnsssdr_malloc((frame_length / 2) * sizeof(int32_t), volk_gnsssdr_get_alignment())); + viterbi_decoder(page_symbols_deint, page_bits); + volk_gnsssdr_free(page_symbols_deint); + + // 3. Call the Galileo page decoder + std::string page_String; + for (int32_t i = 0; i < frame_length; i++) + { + if (page_bits[i] > 0) + { + page_String.push_back('1'); + } + else + { + page_String.push_back('0'); + } + } + volk_gnsssdr_free(page_bits); + + // DECODE COMPLETE WORD (even + odd) and TEST CRC + d_fnav_nav.split_page(page_String); + if (d_fnav_nav.flag_CRC_test == true) + { + LOG(INFO) << "Galileo E5a CRC correct in channel " << d_channel << " from satellite " << d_satellite; + } + else + { + LOG(INFO) << "Galileo E5a CRC error in channel " << d_channel << " from satellite " << d_satellite; + } + + // 4. Push the new navigation data to the queues + if (d_fnav_nav.have_new_ephemeris() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_ephemeris()); + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_fnav_nav.have_new_iono_and_GST() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_iono()); + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } + if (d_fnav_nav.have_new_utc_model() == true) + { + std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_utc_model()); + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; + this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); + } +} + +void galileo_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite) +{ + d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN()); + DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite; + DLOG(INFO) << "Navigation Satellite set to " << d_satellite; +} + + +void galileo_telemetry_decoder_cc::set_channel(int32_t channel) +{ + d_channel = channel; + LOG(INFO) << "Navigation channel set to " << channel; + // ############# ENABLE DATA FILE LOG ################# + if (d_dump == true) + { + if (d_dump_file.is_open() == false) + { + try + { + d_dump_filename = "telemetry"; + d_dump_filename.append(boost::lexical_cast(d_channel)); + d_dump_filename.append(".dat"); + d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary); + LOG(INFO) << "Telemetry decoder dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str(); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what(); + } + } + } +} + + +int galileo_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), + gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) +{ + int32_t corr_value = 0; + int32_t preamble_diff = 0; + + Gnss_Synchro **out = reinterpret_cast(&output_items[0]); // Get the output buffer pointer + const Gnss_Synchro **in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + + Gnss_Synchro current_symbol; // structure to save the synchronization information and send the output object to the next block + // 1. Copy the current tracking output + current_symbol = in[0][0]; + // add new symbol to the symbol queue + d_symbol_history.push_back(current_symbol.Prompt_I); + d_sample_counter++; // count for the processed samples + consume_each(1); + d_flag_preamble = false; + + if (d_symbol_history.size() > d_required_symbols) + { + // TODO Optimize me! + // ******* preamble correlation ******** + for (int32_t i = 0; i < d_samples_per_preamble; i++) + { + if (d_symbol_history.at(i) < 0.0) // symbols clipping + { + corr_value -= d_preamble_samples[i]; + } + else + { + corr_value += d_preamble_samples[i]; + } + } + } + + // ******* frame sync ****************** + switch (d_stat) + { + case 0: // no preamble information + { + if (abs(corr_value) >= d_samples_per_preamble) + { + d_preamble_index = d_sample_counter; // record the preamble sample stamp + LOG(INFO) << "Preamble detection for Galileo satellite " << this->d_satellite; + d_stat = 1; // enter into frame pre-detection status + } + break; + } + case 1: // possible preamble lock + { + if (abs(corr_value) >= d_samples_per_preamble) + { + // check preamble separation + preamble_diff = static_cast(d_sample_counter - d_preamble_index); + if (abs(preamble_diff - d_preamble_period_symbols) == 0) + { + // try to decode frame + LOG(INFO) << "Starting page decoder for Galileo satellite " << this->d_satellite; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + d_stat = 2; + } + else + { + if (preamble_diff > d_preamble_period_symbols) + { + d_stat = 0; // start again + } + } + } + break; + } + case 2: //preamble acquired + { + if (d_sample_counter == d_preamble_index + static_cast(d_preamble_period_symbols)) + { + // call the decoder + switch (d_frame_type) + { + case 1: //INAV + // NEW Galileo page part is received + // 0. fetch the symbols into an array + if (corr_value > 0) //normal PLL lock + { + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = d_symbol_history.at(i + d_samples_per_preamble); // because last symbol of the preamble is just received now! + } + } + else //180 deg. inverted carrier phase PLL lock + { + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = d_symbol_history.at(i + d_samples_per_preamble); // because last symbol of the preamble is just received now! + } + } + decode_INAV_word(d_page_part_symbols, d_frame_length_symbols); + break; + case 2: //FNAV + // NEW Galileo page part is received + // 0. fetch the symbols into an array + if (corr_value > 0) //normal PLL lock + { + int k = 0; + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = 0; + for (uint32_t m = 0; m < d_samples_per_symbol; m++) + { + d_page_part_symbols[i] += static_cast(d_secondary_code_samples[k]) * d_symbol_history.at(i * d_samples_per_symbol + d_samples_per_preamble + m); // because last symbol of the preamble is just received now! + k++; + k = k % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + } + else //180 deg. inverted carrier phase PLL lock + { + int k = 0; + for (uint32_t i = 0; i < d_frame_length_symbols; i++) + { + d_page_part_symbols[i] = 0; + for (uint32_t m = 0; m < d_samples_per_symbol; m++) //integrate samples into symbols + { + d_page_part_symbols[i] -= static_cast(d_secondary_code_samples[k]) * d_symbol_history.at(i * d_samples_per_symbol + d_samples_per_preamble + m); // because last symbol of the preamble is just received now! + k++; + k = k % Galileo_E5a_I_SECONDARY_CODE_LENGTH; + } + } + } + decode_FNAV_word(d_page_part_symbols, d_frame_length_symbols); + break; + default: + return -1; + break; + } + + if (d_inav_nav.flag_CRC_test == true or d_fnav_nav.flag_CRC_test == true) + { + d_CRC_error_counter = 0; + d_flag_preamble = true; // valid preamble indicator (initialized to false every work()) + d_preamble_index = d_sample_counter; // record the preamble sample stamp (t_P) + if (!d_flag_frame_sync) + { + d_flag_frame_sync = true; + DLOG(INFO) << " Frame sync SAT " << this->d_satellite; + } + } + else + { + d_CRC_error_counter++; + d_preamble_index = d_sample_counter; // record the preamble sample stamp + if (d_CRC_error_counter > CRC_ERROR_LIMIT) + { + LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; + d_flag_frame_sync = false; + d_stat = 0; + d_TOW_at_current_symbol_ms = 0; + d_TOW_at_Preamble_ms = 0; + d_fnav_nav.flag_TOW_set = false; + d_inav_nav.flag_TOW_set = false; + } + } + } + break; + } + } + + // UPDATE GNSS SYNCHRO DATA + // 2. Add the telemetry decoder information + if (this->d_flag_preamble == true) + // update TOW at the preamble instant + { + switch (d_frame_type) + { + case 1: //INAV + { + if (d_inav_nav.flag_TOW_set == true) + { + if (d_inav_nav.flag_TOW_5 == true) // page 5 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) + { + // TOW_5 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later plus the decoding delay + d_TOW_at_Preamble_ms = static_cast(d_inav_nav.TOW_5 * 1000.0); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast(GALILEO_INAV_PAGE_PART_MS + (d_required_symbols + 1) * GALILEO_E1_CODE_PERIOD_MS); + d_inav_nav.flag_TOW_5 = false; + } + + else if (d_inav_nav.flag_TOW_6 == true) // page 6 arrived and decoded, so we are in the odd page (since Tow refers to the even page, we have to add 1 sec) + { + // TOW_6 refers to the even preamble, but when we decode it we are in the odd part, so 1 second later plus the decoding delay + d_TOW_at_Preamble_ms = static_cast(d_inav_nav.TOW_6 * 1000.0); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast(GALILEO_INAV_PAGE_PART_MS + (d_required_symbols + 1) * GALILEO_E1_CODE_PERIOD_MS); + d_inav_nav.flag_TOW_6 = false; + } + else + { + // this page has no timing information + d_TOW_at_current_symbol_ms += static_cast(GALILEO_E1_CODE_PERIOD_MS); // + GALILEO_INAV_PAGE_PART_SYMBOLS*GALILEO_E1_CODE_PERIOD; + } + } + break; + } + case 2: //FNAV + { + if (d_fnav_nav.flag_TOW_set == true) + { + if (d_fnav_nav.flag_TOW_1 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_1 * 1000.0); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_1 = false; + } + else if (d_fnav_nav.flag_TOW_2 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_2 * 1000.0); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_2 = false; + } + else if (d_fnav_nav.flag_TOW_3 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_3 * 1000.0); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_3 = false; + } + else if (d_fnav_nav.flag_TOW_4 == true) + { + d_TOW_at_Preamble_ms = static_cast(d_fnav_nav.FNAV_TOW_4 * 1000.0); + //d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD_MS); + d_TOW_at_current_symbol_ms = d_TOW_at_Preamble_ms + static_cast((d_required_symbols + 1) * GALILEO_E5a_CODE_PERIOD_MS); + d_fnav_nav.flag_TOW_4 = false; + } + else + { + d_TOW_at_current_symbol_ms += static_cast(GALILEO_E5a_CODE_PERIOD_MS); + } + break; + } + } + } + } + else // if there is not a new preamble, we define the TOW of the current symbol + { + switch (d_frame_type) + { + case 1: //INAV + { + if (d_inav_nav.flag_TOW_set == true) + { + d_TOW_at_current_symbol_ms += d_PRN_code_period_ms; + } + break; + } + case 2: //FNAV + { + if (d_fnav_nav.flag_TOW_set == true) + { + d_TOW_at_current_symbol_ms += d_PRN_code_period_ms; + } + break; + } + } + } + + // remove used symbols from history + // todo: Use circular buffer here + if (d_symbol_history.size() > d_required_symbols) + { + d_symbol_history.pop_front(); + } + + switch (d_frame_type) + { + case 1: //INAV + { + if (d_inav_nav.flag_TOW_set) + { + if (d_inav_nav.flag_GGTO_1 == true and d_inav_nav.flag_GGTO_2 == true and d_inav_nav.flag_GGTO_3 == true and d_inav_nav.flag_GGTO_4 == true) // all GGTO parameters arrived + { + delta_t = d_inav_nav.A_0G_10 + d_inav_nav.A_1G_10 * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - d_inav_nav.t_0G_10 + 604800.0 * (fmod((d_inav_nav.WN_0 - d_inav_nav.WN_0G_10), 64.0))); + } + + current_symbol.Flag_valid_word = true; + } + break; + } + + case 2: //FNAV + { + if (d_fnav_nav.flag_TOW_set) + { + current_symbol.Flag_valid_word = true; + } + break; + } + } + + if (d_inav_nav.flag_TOW_set or d_fnav_nav.flag_TOW_set) + { + current_symbol.TOW_at_current_symbol_ms = d_TOW_at_current_symbol_ms; + // todo: Galileo to GPS time conversion should be moved to observable block. + // current_symbol.TOW_at_current_symbol_ms -= delta_t; //Galileo to GPS TOW + + if (d_dump == true) + { + // MULTIPLEXED FILE RECORDING - Record results to file + try + { + double tmp_double; + uint64_t tmp_ulong_int; + tmp_double = static_cast(d_TOW_at_current_symbol_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + tmp_ulong_int = current_symbol.Tracking_sample_counter; + d_dump_file.write(reinterpret_cast(&tmp_ulong_int), sizeof(uint64_t)); + tmp_double = static_cast(d_TOW_at_Preamble_ms) / 1000.0; + d_dump_file.write(reinterpret_cast(&tmp_double), sizeof(double)); + } + catch (const std::ifstream::failure &e) + { + LOG(WARNING) << "Exception writing observables dump file " << e.what(); + } + } + // 3. Make the output (copy the object contents to the GNURadio reserved memory) + *out[0] = current_symbol; + return 1; + } + else + { + return 0; + } +} diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.h similarity index 62% rename from src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.h rename to src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.h index 663c365b2..f67418868 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_e1b_telemetry_decoder_cc.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_cc.h @@ -1,8 +1,7 @@ /*! - * \file galileo_e1b_telemetry_decoder_cc.h - * \brief Interface of a Galileo INAV message demodulator block - * \author Javier Arribas 2013 jarribas(at)cttc.es, - * Mara Branzanti 2013 mara.branzanti(at)gmail.com + * \file galileo_telemetry_decoder_cc.h + * \brief Implementation of a Galileo unified INAV and FNAV message demodulator block + * \author Javier Arribas 2018. jarribas(at)cttc.es * * ------------------------------------------------------------------------- * @@ -29,12 +28,15 @@ * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_GALILEO_E1B_TELEMETRY_DECODER_CC_H -#define GNSS_SDR_GALILEO_E1B_TELEMETRY_DECODER_CC_H + +#ifndef GNSS_SDR_galileo_telemetry_decoder_cc_H +#define GNSS_SDR_galileo_telemetry_decoder_cc_H #include "Galileo_E1.h" +#include "Galileo_E5a.h" #include "galileo_navigation_message.h" +#include "galileo_fnav_message.h" #include "galileo_ephemeris.h" #include "galileo_almanac.h" #include "galileo_iono.h" @@ -46,20 +48,20 @@ #include -class galileo_e1b_telemetry_decoder_cc; +class galileo_telemetry_decoder_cc; -typedef boost::shared_ptr galileo_e1b_telemetry_decoder_cc_sptr; +typedef boost::shared_ptr galileo_telemetry_decoder_cc_sptr; -galileo_e1b_telemetry_decoder_cc_sptr galileo_e1b_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); +galileo_telemetry_decoder_cc_sptr galileo_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump); /*! - * \brief This class implements a block that decodes the INAV data defined in Galileo ICD + * \brief This class implements a block that decodes the INAV and FNAV data defined in Galileo ICD * */ -class galileo_e1b_telemetry_decoder_cc : public gr::block +class galileo_telemetry_decoder_cc : public gr::block { public: - ~galileo_e1b_telemetry_decoder_cc(); + ~galileo_telemetry_decoder_cc(); void set_satellite(const Gnss_Satellite &satellite); //!< Set satellite PRN void set_channel(int32_t channel); //!< Set receiver's channel int32_t flag_even_word_arrived; @@ -71,23 +73,30 @@ public: gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); private: - friend galileo_e1b_telemetry_decoder_cc_sptr - galileo_e1b_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); - galileo_e1b_telemetry_decoder_cc(const Gnss_Satellite &satellite, bool dump); + friend galileo_telemetry_decoder_cc_sptr + galileo_make_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump); + galileo_telemetry_decoder_cc(const Gnss_Satellite &satellite, int frame_type, bool dump); void viterbi_decoder(double *page_part_symbols, int32_t *page_part_bits); void deinterleaver(int32_t rows, int32_t cols, double *in, double *out); - void decode_word(double *symbols, int32_t frame_length); + void decode_INAV_word(double *symbols, int32_t frame_length); + void decode_FNAV_word(double *page_symbols, int32_t frame_length); - uint16_t d_preambles_bits[GALILEO_INAV_PREAMBLE_LENGTH_BITS]; - - int32_t *d_preambles_symbols; + int d_frame_type; + int32_t d_bits_per_preamble; + int32_t d_samples_per_preamble; + int32_t d_preamble_period_symbols; + int32_t *d_preamble_samples; + int32_t *d_secondary_code_samples; uint32_t d_samples_per_symbol; - int32_t d_symbols_per_preamble; + uint32_t d_PRN_code_period_ms; + uint32_t d_required_symbols; + uint32_t d_frame_length_symbols; + double *d_page_part_symbols; - std::deque d_symbol_history; + std::deque d_symbol_history; uint64_t d_sample_counter; uint64_t d_preamble_index; @@ -99,7 +108,8 @@ private: int32_t d_CRC_error_counter; // navigation message vars - Galileo_Navigation_Message d_nav; + Galileo_Navigation_Message d_inav_nav; + Galileo_Fnav_Message d_fnav_nav; bool d_dump; Gnss_Satellite d_satellite; @@ -120,8 +130,8 @@ private: const int32_t nn = 2; // Coding rate 1/n const int32_t KK = 7; // Constraint Length int32_t mm = KK - 1; - const int32_t CodeLength = 240; - int32_t DataLength = (CodeLength / nn) - mm; + int32_t CodeLength; + int32_t DataLength; }; #endif diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc index 815ff2c88..374cb910f 100755 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc @@ -238,17 +238,18 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_) : gr::bl d_correlation_length_ms = 1; d_code_samples_per_chip = 1; d_code_length_chips = static_cast(Galileo_E5a_CODE_LENGTH_CHIPS); - d_secondary = true; + if (trk_parameters.track_pilot) { + d_secondary = true; d_secondary_code_length = static_cast(Galileo_E5a_Q_SECONDARY_CODE_LENGTH); signal_pretty_name = signal_pretty_name + "Q"; interchange_iq = true; } else { - d_secondary_code_length = static_cast(Galileo_E5a_I_SECONDARY_CODE_LENGTH); - d_secondary_code_string = const_cast(&Galileo_E5a_I_SECONDARY_CODE); + //Do not acquire secondary code in data component. It is done in telemetry decoder + d_secondary = false; signal_pretty_name = signal_pretty_name + "I"; interchange_iq = false; } @@ -497,7 +498,7 @@ void dll_pll_veml_tracking::start_tracking() for (uint32_t i = 0; i < d_code_length_chips; i++) { d_tracking_code[i] = aux_code[i].imag(); - d_data_code[i] = aux_code[i].real(); + d_data_code[i] = aux_code[i].real(); //the same because it is generated the full signal (E5aI + E5aQ) } d_Prompt_Data[0] = gr_complex(0.0, 0.0); correlator_data_cpu.set_local_code_and_taps(d_code_length_chips, d_data_code, d_prompt_data_shift); diff --git a/src/core/system_parameters/Galileo_E1.h b/src/core/system_parameters/Galileo_E1.h index b1d2e6191..e25501e08 100644 --- a/src/core/system_parameters/Galileo_E1.h +++ b/src/core/system_parameters/Galileo_E1.h @@ -59,6 +59,7 @@ const double Galileo_E1_SUB_CARRIER_A_RATE_HZ = 1.023e6; //!< Galileo E1 sub-ca const double Galileo_E1_SUB_CARRIER_B_RATE_HZ = 6.138e6; //!< Galileo E1 sub-carrier 'b' rate [Hz] const double Galileo_E1_B_CODE_LENGTH_CHIPS = 4092.0; //!< Galileo E1-B code length [chips] const double Galileo_E1_B_SYMBOL_RATE_BPS = 250.0; //!< Galileo E1-B symbol rate [bits/second] +const int32_t Galileo_E1_B_SAMPLES_PER_SYMBOL = 1; //!< (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS) / Galileo_E1_B_SYMBOL_RATE_BPS const int32_t Galileo_E1_C_SECONDARY_CODE_LENGTH = 25; //!< Galileo E1-C secondary code length [chips] const int32_t Galileo_E1_NUMBER_OF_CODES = 50; @@ -70,10 +71,7 @@ const int32_t GALILEO_E1_HISTORY_DEEP = 100; // Galileo INAV Telemetry structure -#define GALILEO_INAV_PREAMBLE \ - { \ - 0, 1, 0, 1, 1, 0, 0, 0, 0, 0 \ - } +const std::string GALILEO_INAV_PREAMBLE = {"0101100000"}; const int32_t GALILEO_INAV_PREAMBLE_LENGTH_BITS = 10; const double GALILEO_INAV_PAGE_PART_WITH_PREABLE_SECONDS = 2.0 + GALILEO_INAV_PREAMBLE_LENGTH_BITS * Galileo_E1_CODE_PERIOD;