From 76bbd3c3bbc304b871ee755b7a283d8aa707a44b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 8 Nov 2020 14:10:43 +0100 Subject: [PATCH] Add work on the Galileo E6 message decoding up to HAS page CRC check --- docs/changelog.md | 5 +- .../galileo_telemetry_decoder_gs.cc | 96 +++++++++++++++---- .../galileo_telemetry_decoder_gs.h | 3 +- src/core/system_parameters/CMakeLists.txt | 7 +- src/core/system_parameters/Galileo_CNAV.h | 53 ++++++++++ .../system_parameters/galileo_cnav_message.cc | 71 ++++++++++++++ .../system_parameters/galileo_cnav_message.h | 61 ++++++++++++ 7 files changed, 270 insertions(+), 26 deletions(-) create mode 100644 src/core/system_parameters/Galileo_CNAV.h create mode 100644 src/core/system_parameters/galileo_cnav_message.cc create mode 100644 src/core/system_parameters/galileo_cnav_message.h diff --git a/docs/changelog.md b/docs/changelog.md index 16bdd54d9..d0e123d5e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -27,8 +27,9 @@ SPDX-FileCopyrightText: 2011-2020 Carles Fernandez-Prades (GALILEO_E6_CODE_PERIOD_MS); - d_bits_per_preamble = 16; // Not available - d_samples_per_preamble = 16; // Not available - d_preamble_period_symbols = 1000; // Not available - d_required_symbols = 1000 + d_samples_per_preamble; // Not available - d_preamble_samples.reserve(d_samples_per_preamble); // Not available - d_frame_length_symbols = d_preamble_period_symbols - d_samples_per_preamble; // Not available - d_codelength = d_preamble_period_symbols - d_samples_per_preamble; // Not available - d_datalength = (d_codelength / d_nn) - d_mm; // Not available - d_max_symbols_without_valid_frame = d_preamble_period_symbols * 10; // Not available + d_bits_per_preamble = GALILEO_CNAV_PREAMBLE_LENGTH_BITS; + d_samples_per_preamble = GALILEO_CNAV_PREAMBLE_LENGTH_BITS; + d_preamble_period_symbols = GALILEO_CNAV_SYMBOLS_PER_PAGE; + d_required_symbols = static_cast(GALILEO_CNAV_SYMBOLS_PER_PAGE) + d_samples_per_preamble; + d_preamble_samples.reserve(d_samples_per_preamble); + d_frame_length_symbols = GALILEO_CNAV_SYMBOLS_PER_PAGE - GALILEO_CNAV_PREAMBLE_LENGTH_BITS; + d_codelength = GALILEO_CNAV_SYMBOLS_PER_PAGE - GALILEO_CNAV_PREAMBLE_LENGTH_BITS; + d_datalength = (d_codelength / d_nn) - d_mm; + d_max_symbols_without_valid_frame = GALILEO_CNAV_SYMBOLS_PER_PAGE * 60; break; } default: @@ -167,8 +167,14 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs( } case 3: // CNAV for E6 { - // TODO - d_preamble_samples[i] = 1; + if (GALILEO_CNAV_PREAMBLE[i] == '1') + { + d_preamble_samples[i] = 1; + } + else + { + d_preamble_samples[i] = -1; + } break; } } @@ -256,14 +262,14 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in page_part_symbols_deint[i] = -page_part_symbols_deint[i]; } } - - std::vector page_part_bits(frame_length / 2); + const int32_t decoded_length = frame_length / 2; + std::vector page_part_bits(decoded_length); viterbi_decoder(page_part_symbols_deint.data(), page_part_bits.data()); // 3. Call the Galileo page decoder std::string page_String; - page_String.reserve(frame_length / 2); - for (int32_t i = 0; i < (frame_length / 2); i++) + page_String.reserve(decoded_length); + for (int32_t i = 0; i < decoded_length; i++) { if (page_part_bits[i] > 0) { @@ -391,13 +397,15 @@ void galileo_telemetry_decoder_gs::decode_FNAV_word(float *page_symbols, int32_t page_symbols_deint[i] = -page_symbols_deint[i]; } } - std::vector page_bits(frame_length / 2); + + const int32_t decoded_length = frame_length / 2; + std::vector page_bits(decoded_length); viterbi_decoder(page_symbols_deint.data(), page_bits.data()); // 3. Call the Galileo page decoder std::string page_String; - page_String.reserve(frame_length); - for (int32_t i = 0; i < frame_length; i++) + page_String.reserve(decoded_length); + for (int32_t i = 0; i < decoded_length; i++) { if (page_bits[i] > 0) { @@ -442,9 +450,55 @@ void galileo_telemetry_decoder_gs::decode_FNAV_word(float *page_symbols, int32_t } -void galileo_telemetry_decoder_gs::decode_CNAV_word(float *page_symbols __attribute__((unused)), int32_t frame_length __attribute__((unused))) +void galileo_telemetry_decoder_gs::decode_CNAV_word(float *page_symbols, int32_t page_length) { + // 1. De-interleave + std::vector page_symbols_deint(page_length); + deinterleaver(GALILEO_CNAV_INTERLEAVER_ROWS, GALILEO_CNAV_INTERLEAVER_COLS, page_symbols, page_symbols_deint.data()); + + // 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 degrees + for (int32_t i = 0; i < page_length; i++) + { + if ((i + 1) % 2 == 0) + { + page_symbols_deint[i] = -page_symbols_deint[i]; + } + } + const int32_t decoded_length = page_length / 2; + std::vector page_bits(decoded_length); + viterbi_decoder(page_symbols_deint.data(), page_bits.data()); + + // 3. Call the Galileo page decoder + std::string page_String; + page_String.reserve(decoded_length); + for (int32_t i = 0; i < decoded_length; i++) + { + if (page_bits[i] > 0) + { + page_String.push_back('1'); + } + else + { + page_String.push_back('0'); + } + } + d_cnav_nav.read_HAS_page(page_String); + + // 4. Check CRC + if (d_cnav_nav.get_flag_CRC_test() == true) + { + DLOG(INFO) << "Galileo E6B CRC correct in channel " << d_channel << " from satellite " << d_satellite; + } + else + { + DLOG(INFO) << "Galileo E6B CRC error in channel " << d_channel << " from satellite " << d_satellite; + } // TODO + // Get full HAS message from different pages + // Reed Solomon decoding + // Retrieve data from message } @@ -679,7 +733,7 @@ int galileo_telemetry_decoder_gs::general_work(int noutput_items __attribute__(( else { d_CRC_error_counter++; - if (d_CRC_error_counter > CRC_ERROR_LIMIT) + if ((d_CRC_error_counter > CRC_ERROR_LIMIT) and (d_frame_type != 3)) { DLOG(INFO) << "Lost of frame sync SAT " << this->d_satellite; d_flag_frame_sync = false; diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h index 899fb6019..46957e2d4 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h @@ -23,7 +23,7 @@ #ifndef GNSS_SDR_GALILEO_TELEMETRY_DECODER_GS_H #define GNSS_SDR_GALILEO_TELEMETRY_DECODER_GS_H - +#include "galileo_cnav_message.h" #include "galileo_fnav_message.h" #include "galileo_inav_message.h" #include "gnss_block_interface.h" @@ -104,6 +104,7 @@ private: Gnss_Satellite d_satellite; // navigation message vars + Galileo_Cnav_Message d_cnav_nav; Galileo_Inav_Message d_inav_nav; Galileo_Fnav_Message d_fnav_nav; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index beaac4b95..ee4648438 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -16,11 +16,12 @@ set(SYSTEM_PARAMETERS_SOURCES galileo_utc_model.cc galileo_ephemeris.cc galileo_almanac_helper.cc + galileo_cnav_message.cc + galileo_fnav_message.cc galileo_inav_message.cc beidou_dnav_navigation_message.cc beidou_dnav_ephemeris.cc sbas_ephemeris.cc - galileo_fnav_message.cc gps_cnav_ephemeris.cc gps_cnav_navigation_message.cc glonass_gnav_ephemeris.cc @@ -43,12 +44,14 @@ set(SYSTEM_PARAMETERS_HEADERS galileo_ephemeris.h galileo_almanac.h galileo_almanac_helper.h + Galileo_CNAV.h Galileo_FNAV.h Galileo_INAV.h galileo_iono.h + galileo_cnav_message.h + galileo_fnav_message.h galileo_inav_message.h sbas_ephemeris.h - galileo_fnav_message.h gps_cnav_ephemeris.h gps_cnav_navigation_message.h gps_cnav_iono.h diff --git a/src/core/system_parameters/Galileo_CNAV.h b/src/core/system_parameters/Galileo_CNAV.h new file mode 100644 index 000000000..a0a3999aa --- /dev/null +++ b/src/core/system_parameters/Galileo_CNAV.h @@ -0,0 +1,53 @@ +/*! + * \file Galileo_CNAV.h + * \brief Galileo CNAV mesage constants. Data from: + * Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2 + * (April 2020). + * \author Carles Fernandez-Prades, 2020. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2020 (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. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GALILEO_CNAV_H +#define GNSS_SDR_GALILEO_CNAV_H + +#include + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + + +// Galileo CNAV message structure +constexpr int32_t GALILEO_CNAV_SYMBOLS_PER_PAGE = 1000; //!< Total numer of symbols per HAS page including the sync pattern +constexpr int32_t GALILEO_CNAV_PREAMBLE_PERIOD_SYMBOLS = 1000; +constexpr int32_t GALILEO_CNAV_PAGE_MS = 1; //!< Duration in ms of a CNAV page +constexpr int32_t GALILEO_CNAV_INTERLEAVER_ROWS = 8; +constexpr int32_t GALILEO_CNAV_INTERLEAVER_COLS = 123; +constexpr int32_t GALILEO_CNAV_TELEMETRY_RATE_BITS_SECOND = 1000; // bps +constexpr int32_t GALILEO_CNAV_HAS_PAGE_DATA_BITS = 448; +constexpr int32_t GALILEO_CNAV_PAGE_RESERVED_BITS = 14; +constexpr int32_t GALILEO_CNAV_BITS_FOR_CRC = GALILEO_CNAV_HAS_PAGE_DATA_BITS + GALILEO_CNAV_PAGE_RESERVED_BITS; // 462 +constexpr int32_t GALILEO_CNAV_BYTES_FOR_CRC = 60; +constexpr int32_t GALILEO_CNAV_MESSAGE_BITS_PER_PAGE = 424; +constexpr int32_t GALILEO_CNAV_PAGE_HEADER_BITS = 24; +constexpr int32_t GALILEO_CNAV_PREAMBLE_LENGTH_BITS = 16; +constexpr char GALILEO_CNAV_PREAMBLE[17] = "1011011101110000"; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_GALILEO_CNAV_H diff --git a/src/core/system_parameters/galileo_cnav_message.cc b/src/core/system_parameters/galileo_cnav_message.cc new file mode 100644 index 000000000..32c121856 --- /dev/null +++ b/src/core/system_parameters/galileo_cnav_message.cc @@ -0,0 +1,71 @@ +/*! + * \file galileo_cnav_message.cc + * \brief Implementation of a Galileo CNAV Data message as described in + * Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2 + * (April 2020) + * \author Carles Fernandez-Prades, 2020 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2020 (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. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "galileo_cnav_message.h" +#include // for boost::crc_basic, boost::crc_optimal +#include // for boost::dynamic_bitset +#include // for reverse + + +using CRC_Galileo_CNAV_type = boost::crc_optimal<24, 0x1864CFBU, 0x0, 0x0, false, false>; + + +bool Galileo_Cnav_Message::CRC_test(std::bitset bits, uint32_t checksum) const +{ + CRC_Galileo_CNAV_type CRC_Galileo; + + // Galileo CNAV frame for CRC is not an integer multiple of bytes + // it needs to be filled with zeroes at the start of the frame. + // This operation is done in the transformation from bits to bytes + // using boost::dynamic_bitset. + boost::dynamic_bitset frame_bits(std::string(bits.to_string())); + + std::vector bytes; + boost::to_block_range(frame_bits, std::back_inserter(bytes)); + std::reverse(bytes.begin(), bytes.end()); + + CRC_Galileo.process_bytes(bytes.data(), GALILEO_CNAV_BYTES_FOR_CRC); + + const uint32_t crc_computed = CRC_Galileo.checksum(); + if (checksum == crc_computed) + { + return true; + } + return false; +} + + +void Galileo_Cnav_Message::read_HAS_page(const std::string& page_string) +{ + const std::string has_page_bits = page_string.substr(0, GALILEO_CNAV_BITS_FOR_CRC); + const std::string CRC_data = page_string.substr(GALILEO_CNAV_BITS_FOR_CRC, 24); + const std::bitset Word_for_CRC_bits(has_page_bits); + const std::bitset<24> checksum(CRC_data); + if (CRC_test(Word_for_CRC_bits, checksum.to_ulong()) == true) + { + flag_CRC_test = true; + // CRC correct: Read HAS page header + } + else + { + flag_CRC_test = false; + } +} diff --git a/src/core/system_parameters/galileo_cnav_message.h b/src/core/system_parameters/galileo_cnav_message.h new file mode 100644 index 000000000..5f664b20f --- /dev/null +++ b/src/core/system_parameters/galileo_cnav_message.h @@ -0,0 +1,61 @@ +/*! + * \file galileo_cnav_message.h + * \brief Implementation of a Galileo CNAV Data message as described in + * Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2 + * (April 2020) + * \author Carles Fernandez-Prades, 2020 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2020 (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. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GALILEO_CNAV_MESSAGE_H +#define GNSS_SDR_GALILEO_CNAV_MESSAGE_H + +#include "Galileo_CNAV.h" +#include +#include +#include + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + + +/*! + * \brief This class handles the Galileo CNAV Data message, as described in the + * Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2 + * (April 2020) + */ +class Galileo_Cnav_Message +{ +public: + Galileo_Cnav_Message() = default; + + void read_HAS_page(const std::string& page_string); + + inline bool get_flag_CRC_test() const + { + return flag_CRC_test; + } + +private: + bool CRC_test(std::bitset bits, uint32_t checksum) const; + bool flag_CRC_test{}; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_GALILEO_CNAV_MESSAGE_H