1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-01-18 21:23:02 +00:00

[TAS-177] implement OsnmaTestVectorsSimulation

This commit introduces two new unit tests for the osnma_msg_receiver class: 'TeslaKeyVerification' and 'OsnmaTestVectorsSimulation'. The first test verifies the Tesla key handling within the class. The second test uses real-world test vectors to simulate osnma message receiving and verifies correct parsing and processing of messages.
This commit is contained in:
cesaaargm 2024-04-19 00:47:31 +02:00
parent 881bb5c58a
commit e13fc39214
6 changed files with 322 additions and 15 deletions

View File

@ -149,6 +149,7 @@ void osnma_msg_receiver::read_nma_header(uint8_t nma_header)
d_osnma_data.d_nma_header.cid = d_dsm_reader->get_cid(nma_header); d_osnma_data.d_nma_header.cid = d_dsm_reader->get_cid(nma_header);
d_osnma_data.d_nma_header.cpks = d_dsm_reader->get_cpks(nma_header); d_osnma_data.d_nma_header.cpks = d_dsm_reader->get_cpks(nma_header);
d_osnma_data.d_nma_header.reserved = d_dsm_reader->get_nma_header_reserved(nma_header); d_osnma_data.d_nma_header.reserved = d_dsm_reader->get_nma_header_reserved(nma_header);
std::cout<< "NMAS: " << static_cast<int>(d_osnma_data.d_nma_header.nmas) << " CPKS: " << static_cast<int>(d_osnma_data.d_nma_header.cpks) << std::endl;
} }
@ -438,7 +439,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
// Check that the padding bits received match the computed values // Check that the padding bits received match the computed values
if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated)
{ {
LOG(WARNING) << "OSNMA: DSM-KROOT message received ok."; LOG(WARNING) << "Galileo OSNMA: DSM-KROOT message received ok.";
std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast<uint32_t>(d_osnma_data.d_nma_header.cid) std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast<uint32_t>(d_osnma_data.d_nma_header.cid)
<< ", PKID=" << static_cast<uint32_t>(d_osnma_data.d_dsm_kroot_message.pkid) << ", PKID=" << static_cast<uint32_t>(d_osnma_data.d_dsm_kroot_message.pkid)
<< ", WN=" << static_cast<uint32_t>(d_osnma_data.d_dsm_kroot_message.wn_k) << ", WN=" << static_cast<uint32_t>(d_osnma_data.d_dsm_kroot_message.wn_k)

View File

@ -18,6 +18,8 @@
#ifndef GNSS_SDR_OSNMA_MSG_RECEIVER_H #ifndef GNSS_SDR_OSNMA_MSG_RECEIVER_H
#define GNSS_SDR_OSNMA_MSG_RECEIVER_H #define GNSS_SDR_OSNMA_MSG_RECEIVER_H
#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test
#include "galileo_inav_message.h" // for OSNMA_msg #include "galileo_inav_message.h" // for OSNMA_msg
#include "gnss_block_interface.h" // for gnss_shared_ptr #include "gnss_block_interface.h" // for gnss_shared_ptr
@ -54,7 +56,6 @@ class osnma_msg_receiver : public gr::block
{ {
public: public:
~osnma_msg_receiver() = default; //!< Default destructor ~osnma_msg_receiver() = default; //!< Default destructor
private: private:
friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath);
osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath);
@ -115,6 +116,9 @@ private:
void remove_verified_tags(); void remove_verified_tags();
void control_tags_awaiting_verify_size(); void control_tags_awaiting_verify_size();
bool verify_macseq(const MACK_message& mack); bool verify_macseq(const MACK_message& mack);
FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification);
FRIEND_TEST(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation);
}; };

View File

@ -1301,4 +1301,38 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA)
#${GNSSSDR_SOURCE_DIR}/src/core, #${GNSSSDR_SOURCE_DIR}/src/core,
#${GNSSSDR_SOURCE_DIR}/src/core/receiver, #${GNSSSDR_SOURCE_DIR}/src/core/receiver,
${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters)
endif()
if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA)
set(OSNMA_MSG_RECEIVER_TEST_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc
${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc)
# Configure the test executable:
if(USE_CMAKE_TARGET_SOURCES)
add_executable(osnma_msg_receiver_test)
target_sources(osnma_msg_receiver_test PRIVATE ${OSNMA_MSG_RECEIVER_TEST_SOURCES})
else()
add_executable(osnma_msg_receiver_test ${OSNMA_MSG_RECEIVER_TEST_SOURCES})
endif()
# Link libraries that gnss_crypto_test requires:
target_link_libraries(osnma_msg_receiver_test
PRIVATE
Boost::thread
Gflags::gflags
Glog::glog
GTest::GTest
GTest::Main
core_libs
)
# Include any directories your test needs for header files:
target_include_directories(osnma_msg_receiver_test
PRIVATE
#${GNSSSDR_SOURCE_DIR}/src/algorithms,
#${GNSSSDR_SOURCE_DIR}/src/core,
#${GNSSSDR_SOURCE_DIR}/src/core/receiver,
${GNSSSDR_SOURCE_DIR}/src/core/system_parameters)
endif() endif()

View File

@ -73,6 +73,7 @@ DECLARE_string(log_dir);
#include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc" #include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc"
#include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc" #include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc"
#include "unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc" #include "unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc"
#include "unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc"
#include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc" #include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc"
#include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc"
#include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc"

View File

@ -8,21 +8,21 @@ TEST(GnssCryptoTest, VerifySignature) {
// "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem"
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>();
// RG example - import crt certificate // RG example - import crt certificate - result: FAIL
// std::vector<uint8_t> message = {0x82, 0x10, 0x49, 0x22, 0x04, 0xE0, 0x60, 0x61, 0x0B, 0xDF, 0x26, 0xD7, 0x7B, 0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; //std::vector<uint8_t> message = {0x82, 0x10, 0x49, 0x22, 0x04, 0xE0, 0x60, 0x61, 0x0B, 0xDF, 0x26, 0xD7, 0x7B, 0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF};
// std::vector<uint8_t> signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; //std::vector<uint8_t> signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB};
// std::vector<uint8_t> publicKey { // PEM format - 1000 bits //std::vector<uint8_t> publicKey { // PEM format - 1000 bits
// 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A,
// //
// 0x4D, 0x46, 0x6B, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4B, 0x6F, 0x5A, 0x49, // 0x4D, 0x46, 0x6B, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4B, 0x6F, 0x5A, 0x49,
// 0x7A, 0x6A, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x41, 0x37, 0x4C, 0x4F, 0x5A, 0x4C, 0x77, 0x67, 0x65, 0x39, 0x32, 0x4C, 0x78, 0x4E, 0x2B, 0x46, 0x6B, 0x59, 0x66, 0x38, 0x74, 0x6F, 0x59, 0x79, 0x44, 0x57, 0x50, 0x2F, 0x0A, 0x6F, 0x4A, 0x46, 0x42, 0x44, 0x38, 0x46, 0x59, 0x2B, 0x37, // 0x7A, 0x6A, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x41, 0x37, 0x4C, 0x4F, 0x5A, 0x4C, 0x77, 0x67, 0x65, 0x39, 0x32, 0x4C, 0x78, 0x4E, 0x2B, 0x46, 0x6B, 0x59, 0x66, 0x38, 0x74, 0x6F, 0x59, 0x79, 0x44, 0x57, 0x50, 0x2F, 0x0A, 0x6F, 0x4A, 0x46, 0x42, 0x44, 0x38, 0x46, 0x59, 0x2B, 0x37,
// 0x64, 0x35, 0x67, 0x4F, 0x71, 0x49, 0x61, 0x45, 0x32, 0x52, 0x6A, 0x50, 0x41, 0x6E, 0x4B, 0x49, 0x36, 0x38, 0x73, 0x2F, 0x4F, 0x4B, 0x2F, 0x48, 0x50, 0x67, 0x6F, 0x4C, 0x6B, 0x4F, 0x32, 0x69, 0x6A, 0x51, 0x38, 0x78, 0x41, 0x5A, 0x79, 0x44, 0x64, 0x50, 0x42, 0x31, 0x64, 0x48, 0x53, 0x51, 0x3D, 0x3D, // 0x64, 0x35, 0x67, 0x4F, 0x71, 0x49, 0x61, 0x45, 0x32, 0x52, 0x6A, 0x50, 0x41, 0x6E, 0x4B, 0x49, 0x36, 0x38, 0x73, 0x2F, 0x4F, 0x4B, 0x2F, 0x48, 0x50, 0x67, 0x6F, 0x4C, 0x6B, 0x4F, 0x32, 0x69, 0x6A, 0x51, 0x38, 0x78, 0x41, 0x5A, 0x79, 0x44, 0x64, 0x50, 0x42, 0x31, 0x64, 0x48, 0x53, 0x51, 0x3D, 0x3D,
// //
// 0x0A, // 0x0A,
// 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A } ; // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A } ;
// own ECDSA-P256 key and message generated and signed and verified successfully with openssl // own ECDSA-P256 key and message generated and signed and verified successfully with openssl
std::vector<uint8_t> message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message std::vector<uint8_t> message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed)
std::vector<uint8_t> signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, std::vector<uint8_t> signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A,
0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B,
0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK
@ -56,6 +56,8 @@ TEST(GnssCryptoTest, VerifySignature) {
// 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, 0x41, 0x67, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, 0x41, 0x67, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D,
// 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A }; // 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A };
d_crypto->set_public_key(publicKey); d_crypto->set_public_key(publicKey);
bool result = d_crypto->verify_signature(message, signature); bool result = d_crypto->verify_signature(message, signature);

View File

@ -0,0 +1,265 @@
#include <gtest/gtest.h>
#include <fstream>
#include <osnma_msg_receiver.h>
#include <vector>
#include <bitset>
struct TestVector
{
int svId;
int numNavBits;
std::vector<uint8_t> navBits;
};
class OsnmaMsgReceiverTest : public ::testing::Test
{
protected:
osnma_msg_receiver_sptr osnma;
Galileo_Inav_Message galileo_message;
uint8_t page_position_in_inav_subframe;
bool flag_CRC_test;
std::string page_even;
OSNMA_msg osnma_msg{};
std::array<int8_t, 15> nma_position_filled;
uint32_t d_GST_SIS{}; // 16 AUG 2023 05 00 01
int T {};
uint32_t TOW{};
uint32_t WN{};
void set_time(std::tm& input);
void SetUp() override
{
flag_CRC_test = false;
page_even = "";
std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0};
set_time(input_time);
std::string pemFilePath = "OSNMA_PublicKey_20230803105952_newPKID_1.pem";
std::string merkleFilePath = "OSNMA_MerkleTree_20230803105953_newPKID_1.xml";
osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath);
}
public:
static std::vector<uint8_t> parseNavBits(const std::string& hex);
static std::vector<TestVector> readTestVectorsFromFile(const std::string& filename);
std::string bytes_to_str(const std::vector<uint8_t>& bytes);
std::vector<uint8_t> extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes);
};
TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) {
// Arrange
osnma->d_tesla_key_verified = false;
osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF};
osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits
osnma->d_receiver_time = 345630;
osnma->d_GST_0 = 345600;
osnma->d_tesla_keys.insert((std::pair<uint32_t, std::vector<uint8_t>>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92})));
std::vector<uint8_t> key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB};
uint32_t TOW = 345630;
// Act
bool result = osnma->verify_tesla_key(key, TOW);
// Assert
ASSERT_TRUE(result); // Adjust this according to what you expect
}
TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation)
{
// Arrange
std::vector<TestVector> testVectors = readTestVectorsFromFile(/*"/home/cgm/CLionProjects/osnma/src/tests/data/*/"16_AUG_2023_GST_05_00_01.csv");
bool end_of_hex_stream{false};
int offset_byte{0};
int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size
const int SIZE_PAGE_BYTES{240/8};
const int SIZE_SUBFRAME_PAGES{15};
const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES};
const int DURATION_SUBFRAME{30};
std::cout << "OsnmaTestVectorsSimulation:" << std::endl;
std::cout << "d_GST_SIS: " << d_GST_SIS << std::endl;
std::cout << "T: " << T << std::endl;
std::cout << "TOW: " << TOW << std::endl;
std::cout << "WN: " << WN << std::endl;
// Act
while (end_of_hex_stream == false){ // loop over all bytes of data. Note all TestVectors have same amount of data.
for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe
auto osnmaMsg_sptr = std::make_shared<OSNMA_msg>();
std::array<uint8_t, 15> hkroot{};
std::array<uint32_t, 15> mack{};
byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes)
for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe
{
// extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index
std::vector<uint8_t> page_bytes = extract_page_bytes(tv,byte_index,SIZE_PAGE_BYTES);
if(page_bytes.empty()){
std::cout<< "OsnmaTestVectorsSimulation: end of TestVectors \n" << "byte_index="<<byte_index<< " expected= " << 432000/8 << std::endl;
end_of_hex_stream = true;
break;
}
// convert them to bitset representation using bytes_to_string
std::string page_bits = bytes_to_str(page_bytes);
// Extract the 40 OSNMA bits starting from the 18th bit
std::string even_page = page_bits.substr(0, page_bits.size() / 2);;
std::string odd_page = page_bits.substr( page_bits.size() / 2);
if(even_page.size() < 120 || odd_page.size() < 120 ){
std::cout<< "OsnmaTestVectorsSimulation: error parsing pages" << std::endl;
}
bool even_odd_OK = even_page[0] == '0' && odd_page[0] == '1';
bool page_type_OK = even_page[1] == '0' && odd_page[1] == '0';
bool tail_bits_OK = even_page.substr(even_page.size() - 6) == "000000" && odd_page.substr(odd_page.size() - 6) == "000000";
if(!even_odd_OK || !page_type_OK || !tail_bits_OK)
std::cerr<< "OsnmaTestVectorsSimulation: error parsing pages." << std::endl;
std::bitset<40> osnmaBits(odd_page.substr(18, 40));
// Extract bits for hkroot and mack
std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8));
std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32));
hkroot[idx] = static_cast<uint8_t>(hkrootBits.to_ulong());
mack[idx] = static_cast<uint32_t>(mackBits.to_ulong());
byte_index += SIZE_PAGE_BYTES;
}
if(end_of_hex_stream)
break;
osnmaMsg_sptr->hkroot = hkroot;
osnmaMsg_sptr->mack = mack;
osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF;
osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ;
osnmaMsg_sptr->PRN = tv.svId;
auto temp_obj = pmt::make_any(osnmaMsg_sptr);
osnma->msg_handler_osnma(temp_obj); // osnma entry point
}
if(!end_of_hex_stream){
offset_byte = byte_index; // update offset for the next subframe
d_GST_SIS += DURATION_SUBFRAME;
T = d_GST_SIS % 30;
TOW = d_GST_SIS & 0x000FFFFF;
WN = (d_GST_SIS & 0xFFF00000) >> 20 ;
std::cout << "OsnmaTestVectorsSimulation:" << std::endl;
std::cout << "d_GST_SIS: " << d_GST_SIS << std::endl;
std::cout << "T: " << T << std::endl;
std::cout << "TOW: " << TOW << std::endl;
std::cout << "WN: " << WN << std::endl;
}
}
// Assert
// TODO
}
std::vector<TestVector> OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename)
{
std::ifstream file(filename);
std::vector<TestVector> testVectors;
if (!file.is_open()) {
std::cerr<<"Error reading the file \"" << filename <<"\" \n";
return testVectors;
}
std::string line;
std::getline(file, line);
if (line != "SVID,NumNavBits,NavBitsHEX\r" ){
std::cerr<<"Error parsing first line" <<"\n";
}
while (std::getline(file, line))
{
std::stringstream ss(line);
TestVector tv;
std::string val;
std::getline(ss, val, ',');
tv.svId = std::stoi(val);
std::getline(ss, val, ',');
tv.numNavBits = std::stoi(val);
std::getline(ss, val, ',');
tv.navBits = OsnmaMsgReceiverTest::parseNavBits(val);
testVectors.push_back(tv);
}
return testVectors;
}
std::vector<uint8_t> OsnmaMsgReceiverTest::parseNavBits(const std::string& hex)
{
std::vector<uint8_t> bytes;
for (unsigned int i = 0; i < hex.length()-1; i += 2)
{
std::string byteString = hex.substr(i, 2);
uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16);
bytes.push_back(byte);
}
return bytes;
}
std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector<uint8_t>& bytes)
{
std::string bit_string;
bit_string.reserve(bytes.size() * 8);
for(const auto& byte : bytes)
{
std::bitset<8> bits(byte);
bit_string += bits.to_string();
}
return bit_string;
}
std::vector<uint8_t> OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes)
{
// Ensure we don't go beyond the end of tv.navBits
int num_bytes_to_extract = std::min(num_bytes, static_cast<int>(tv.navBits.size() - byte_index));
// If byte_index is beyond the end of tv.navBits, return an empty vector
if (num_bytes_to_extract <= 0)
{
return std::vector<uint8_t>();
}
// Use std::next to get an iterator to the range to extract
std::vector<uint8_t> extracted_bytes(tv.navBits.begin() + byte_index, tv.navBits.begin() + byte_index + num_bytes_to_extract);
return extracted_bytes;
}
void OsnmaMsgReceiverTest::set_time(std::tm& input)
{
// GST epoch (start of GST time)
std::tm tm_epoch = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0};
auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&tm_epoch));
auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input));
// Get the duration from epoch in seconds
auto duration_sec = std::chrono::duration_cast<std::chrono::seconds>(input_time_point - epoch_time_point);
// Calculate the week number (WN) and time of week (TOW)
uint32_t sec_in_week = 7 * 24 * 60 * 60;
uint32_t week_number = duration_sec.count() / sec_in_week;
uint32_t time_of_week = duration_sec.count() % sec_in_week;
this->WN = week_number;
this->TOW = time_of_week;
// Return the week number and time of week as a pair
this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF);
this->T = d_GST_SIS % 30;
}