mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-30 23:03:05 +00:00 
			
		
		
		
	[TAS-227] [BUG] Tag verification fails for .dat files (WIP)
WIP
This commit is contained in:
		| @@ -439,6 +439,35 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in | ||||
|         } | ||||
|  | ||||
|     // 4. Push the new navigation data to the queues | ||||
|     // extract OSNMA bits, reset container. | ||||
|     bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; | ||||
|     if(check_size_is_ok) | ||||
|         { | ||||
|             std::cout << "Galileo OSNMA: new ADKD=0/12 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW5() - 25 <<std::endl; | ||||
|             const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string,uint32_t>>( // < PRNd , navDataBits, TOW_Sosf> | ||||
|                 d_satellite.get_PRN(), | ||||
|                 d_inav_nav.get_osnma_adkd_0_12_nav_bits(), | ||||
|                 d_inav_nav.get_TOW5() - 25); | ||||
|             this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); | ||||
|             LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast<int>(d_satellite.get_PRN()) << ", TOW=" << static_cast<int>(d_inav_nav.get_TOW5() - 25) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); | ||||
|             d_inav_nav.reset_osnma_nav_bits_adkd0_12(); | ||||
|         } | ||||
|  | ||||
|     check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; | ||||
|     if(check_size_is_ok) | ||||
|         { | ||||
|             std::cout << "Galileo OSNMA: new ADKD=4 navData from " << d_satellite <<" at TOW_sf=" << d_inav_nav.get_TOW6() - 5 <<std::endl; | ||||
|  | ||||
|             const auto tmp_obj = std::make_shared<std::tuple<uint32_t, std::string,uint32_t>>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe | ||||
|                 d_satellite.get_PRN(), | ||||
|                 d_inav_nav.get_osnma_adkd_4_nav_bits(), | ||||
|                 d_inav_nav.get_TOW6() - 5); | ||||
|             this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); | ||||
|             LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast<int>(d_satellite.get_PRN()) << ", TOW=" << static_cast<int>(d_inav_nav.get_TOW6() - 5) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); | ||||
|             d_inav_nav.reset_osnma_nav_bits_adkd4(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|     if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!) | ||||
|         { | ||||
|             // get object for this SV (mandatory) | ||||
| @@ -472,20 +501,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in | ||||
|             d_first_eph_sent = true;  // do not send reduced CED anymore, since we have the full ephemeris set | ||||
|  | ||||
| //            d_flag_osnma_adkd_0_12 = true; // W1-> W5 available | ||||
|             // extract bits, reset container. | ||||
|             bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; | ||||
|             if(check_size_is_ok) | ||||
|                 { | ||||
|                     std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW5() - 24 <<std::endl; | ||||
|                     const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string,uint32_t>>( // < PRNd , navDataBits, TOW_Sosf> | ||||
|                         d_satellite.get_PRN(), | ||||
|                         d_inav_nav.get_osnma_adkd_0_12_nav_bits(), | ||||
|                         d_inav_nav.get_TOW5() - 24); | ||||
|                     this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); | ||||
|                     d_inav_nav.reset_osnma_nav_bits_adkd0_12(); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|         } | ||||
|     else | ||||
|         { | ||||
| @@ -615,19 +630,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in | ||||
|     //    bool adkd_4_nav_data_available = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; // newApproach: let decoder decide when block starts and let it fill the data, and just check for length | ||||
|     if(adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) | ||||
|         { | ||||
|             bool check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; | ||||
|             if(check_size_is_ok) | ||||
|                 { | ||||
|                     std::cout << "Galileo OSNMA: sending ADKD=4 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW6() - 4 <<std::endl; | ||||
|  | ||||
|                     const auto tmp_obj = std::make_shared<std::tuple<uint32_t, std::string,uint32_t>>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe | ||||
|                         d_satellite.get_PRN(), | ||||
|                         d_inav_nav.get_osnma_adkd_4_nav_bits(), | ||||
|                         d_inav_nav.get_TOW6() - 4); | ||||
|                     this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); | ||||
|                     d_inav_nav.reset_osnma_nav_bits_adkd4(); | ||||
|                 } | ||||
|  | ||||
|         } | ||||
|     auto newOSNMA = d_inav_nav.have_new_nma(); | ||||
|     if (d_band == '1' && newOSNMA) | ||||
|   | ||||
| @@ -62,13 +62,13 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, | ||||
|  | ||||
|  | ||||
| osnma_msg_receiver::osnma_msg_receiver( | ||||
|     const std::string& pemFilePath, | ||||
|     const std::string& crtFilePath, | ||||
|     const std::string& merkleFilePath) : gr::block("osnma_msg_receiver", | ||||
|                                              gr::io_signature::make(0, 0, 0), | ||||
|                                              gr::io_signature::make(0, 0, 0)) | ||||
| { | ||||
|     d_dsm_reader = std::make_unique<OSNMA_DSM_Reader>(); | ||||
|     d_crypto = std::make_unique<Gnss_Crypto>(pemFilePath, merkleFilePath); | ||||
|     d_crypto = std::make_unique<Gnss_Crypto>(crtFilePath, merkleFilePath); | ||||
|     d_helper = std::make_unique<Osnma_Helper>(); | ||||
|     //  register OSNMA input message port from telemetry blocks | ||||
|     this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); | ||||
| @@ -101,7 +101,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) | ||||
|                     const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN);  // TODO remove if unneeded | ||||
|  | ||||
|                     std::ostringstream output_message; | ||||
|                     output_message << "Galileo OSNMA: Subframe received starting at " | ||||
|                     output_message << "Galileo OSNMA: complete OSNMA message received starting at " | ||||
|                         << "WN=" | ||||
|                         << nma_msg->WN_sf0 | ||||
|                         << ", TOW=" | ||||
| @@ -125,14 +125,14 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) | ||||
|                     // iono data => 549 bits, utc data, 141 bits. | ||||
|                     if (nav_data.size() == 549) | ||||
|                         { | ||||
|                             LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " | ||||
|                                       << "TOW_sf=" << TOW; | ||||
| //                            LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " | ||||
| //                                      << "TOW_sf=" << TOW; | ||||
|                             d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = nav_data; | ||||
|                         } | ||||
|                     else if (nav_data.size() == 141) | ||||
|                         { | ||||
|                             LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " | ||||
|                                       << "TOW_sf=" << TOW; | ||||
| //                            LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " | ||||
| //                                      << "TOW_sf=" << TOW; | ||||
|                             d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; | ||||
|                         } | ||||
|                     else | ||||
| @@ -322,8 +322,8 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr<OSNMA_msg | ||||
|         { | ||||
|             d_tags_allowed = tags_to_verify::all; | ||||
|             d_tags_to_verify = {0, 4, 12}; | ||||
|             LOG(INFO) << "Galileo OSNMA: time constraint OK (" << delta_T; | ||||
|             LOG(INFO) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; | ||||
|             LOG(INFO) << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)"; | ||||
| //            LOG(INFO) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; | ||||
|             // std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast<int>(d_receiver_time - d_GST_SIS)<< " | < " << static_cast<int>(d_T_L) << " ]" << std::endl; | ||||
|  | ||||
|             // TODO set flag to false to avoid processing dsm and MACK messages | ||||
| @@ -914,13 +914,25 @@ void osnma_msg_receiver::process_mack_message() | ||||
|                     bool ret = verify_macseq(*mack); | ||||
|                     if (ret || d_flag_debug) | ||||
|                         { | ||||
|                             LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; | ||||
|                             for (std::size_t i = 0; i < mack->tag_and_info.size(); ++i) | ||||
|                                 { | ||||
|                                     // add tags of current mack to the verification queue | ||||
|                                     auto& tag = mack->tag_and_info[i]; | ||||
|                                     Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2);  // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. | ||||
|                                     d_tags_awaiting_verify.insert(std::pair<uint32_t, Tag>(mack->TOW, t)); | ||||
|                                     LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; | ||||
|                                     LOG(INFO) << "Galileo OSNMA: Add Tag Id= " | ||||
|                                               << t.tag_id | ||||
|                                               << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase | ||||
|                                               << t.received_tag << std::dec | ||||
|                                               << ", TOW=" | ||||
|                                               << t.TOW | ||||
|                                               << ", ADKD=" | ||||
|                                               << static_cast<unsigned>(t.ADKD) | ||||
|                                               << ", PRNa=" | ||||
|                                               << static_cast<unsigned>(t.PRNa) | ||||
|                                               << ", PRNd=" | ||||
|                                               << static_cast<unsigned>(t.PRN_d); | ||||
|                                 } | ||||
|                             std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; | ||||
|                             mack = d_macks_awaiting_MACSEQ_verification.erase(mack); | ||||
| @@ -1070,6 +1082,11 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) | ||||
|  | ||||
| bool osnma_msg_receiver::verify_tag(Tag& tag) | ||||
| { | ||||
|     // Debug | ||||
|     LOG(INFO) << "Galileo OSNMA: Tag verification :: Start for tag Id= " | ||||
|               << tag.tag_id | ||||
|               << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase | ||||
|               << tag.received_tag << std::dec; | ||||
|     // TODO case tag0, to be verified here?, PRNd not needed for it | ||||
|     // build message | ||||
|     std::vector<uint8_t> m = build_message(tag); | ||||
| @@ -1077,9 +1094,16 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) | ||||
|     std::vector<uint8_t> mac; | ||||
|     std::vector<uint8_t> applicable_key; | ||||
|     if (tag.ADKD == 0 || tag.ADKD == 4) | ||||
|         { | ||||
|             applicable_key = d_tesla_keys[tag.TOW + 30]; | ||||
|             LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<<static_cast<int>(tag.TOW + 30); | ||||
|         } | ||||
|         else  // ADKD 12 | ||||
|             { | ||||
|                 applicable_key = d_tesla_keys[tag.TOW + 330]; | ||||
|                 LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<<static_cast<int>(tag.TOW + 330); | ||||
|             } | ||||
|  | ||||
|  | ||||
|     if (d_osnma_data.d_dsm_kroot_message.mf == 0)  // C: HMAC-SHA-256 | ||||
|         { | ||||
| @@ -1142,7 +1166,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) | ||||
|                       << ", PRNa=" | ||||
|                       << static_cast<unsigned>(tag.PRNa) | ||||
|                       << ", PRNd=" | ||||
|                       << static_cast<unsigned>(tag.PRN_d); | ||||
|                       << static_cast<unsigned>(tag.PRN_d) << std::endl; | ||||
|             return true; | ||||
|         } | ||||
|     return false; | ||||
| @@ -1171,10 +1195,12 @@ std::vector<uint8_t> osnma_msg_receiver::build_message(const Tag& tag) | ||||
|     if (tag.ADKD == 0 || tag.ADKD == 12)  // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. | ||||
|         { | ||||
|             applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; | ||||
|             LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast<int>(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; | ||||
|         } | ||||
|     else if (tag.ADKD == 4) | ||||
|         { | ||||
|             applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; | ||||
|             LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast<int>(tag.PRN_d)  << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; | ||||
|         } | ||||
|     else | ||||
|         LOG(WARNING) << "Galileo OSNMA :: Tag verification :: unknown ADKD"; | ||||
| @@ -1484,7 +1510,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) | ||||
|     if (prn_it != d_satellite_nav_data.end()) | ||||
|         { | ||||
|             // PRN was found, check if TOW exists in inner map | ||||
|             LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; | ||||
|             //LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; | ||||
|             std::map<uint32_t, NavData>& tow_map = prn_it->second; | ||||
|             auto tow_it = tow_map.find(t.TOW - 30); | ||||
|             if (tow_it != tow_map.end()) | ||||
| @@ -1500,7 +1526,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) | ||||
|     else | ||||
|         { | ||||
|             // PRN was not found | ||||
|             LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; | ||||
|             //LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; | ||||
|             return false; | ||||
|         } | ||||
|     return false; | ||||
| @@ -1519,7 +1545,7 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t) | ||||
|             auto it = d_tesla_keys.find(t.TOW + 30); | ||||
|             if (it != d_tesla_keys.end()) | ||||
|                 { | ||||
|                     LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; | ||||
|                     //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; | ||||
|                     return true; | ||||
|                 } | ||||
|         } | ||||
| @@ -1528,11 +1554,11 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t) | ||||
|             auto it = d_tesla_keys.find(t.TOW + 330); | ||||
|             if (it != d_tesla_keys.end()) | ||||
|                 { | ||||
|                     LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; | ||||
|                     //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; | ||||
|                     return true; | ||||
|                 } | ||||
|         } | ||||
|     LOG(INFO) << "Galileo OSNMA: hasKey = false "; | ||||
|     //LOG(INFO) << "Galileo OSNMA: hasKey = false "; | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| @@ -1601,6 +1627,6 @@ std::vector<uint8_t> osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede | ||||
|     // compare computed current key against received key | ||||
|     auto end = std::chrono::high_resolution_clock::now(); | ||||
|     std::chrono::duration<double> elapsed = end - start; | ||||
|     LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; | ||||
| //    LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; | ||||
|     return K_II; | ||||
| } | ||||
|   | ||||
| @@ -59,7 +59,7 @@ public: | ||||
|     ~osnma_msg_receiver() = default;  //!< Default destructor | ||||
| private: | ||||
|     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& crtFilePath, const std::string& merkleFilePath); | ||||
|  | ||||
|     void msg_handler_osnma(const pmt::pmt_t& msg); | ||||
|     void process_osnma_message(const std::shared_ptr<OSNMA_msg>& osnma_msg); | ||||
|   | ||||
| @@ -1417,7 +1417,7 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() | ||||
|     nma_position_filled = std::array<int8_t, 15>{}; | ||||
|     // Fill TOW and WN | ||||
|     nma_msg.WN_sf0 = WN_0; | ||||
|     int32_t TOW_sf0 = TOW_5 - 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start | ||||
|     int32_t TOW_sf0 = TOW_5 - 25;//- 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start TODO review | ||||
|     if (TOW_sf0 < 0) | ||||
|         { | ||||
|             TOW_sf0 += 604800; | ||||
|   | ||||
| @@ -16,6 +16,8 @@ | ||||
|  | ||||
| #include "osnma_helper.h" | ||||
| #include <bitset> | ||||
| #include <iomanip> | ||||
| #include <ios> | ||||
|  | ||||
| uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const | ||||
| { | ||||
| @@ -74,3 +76,12 @@ std::string Osnma_Helper::verification_status_str(int status) | ||||
|             default: return "UNKNOWN"; | ||||
|             } | ||||
| } | ||||
| std::string Osnma_Helper::convert_to_hex_string(const std::vector<uint8_t>& vector) | ||||
| { | ||||
|     std::stringstream ss; | ||||
|     ss << std::hex << std::setfill('0'); | ||||
|     for (auto byte : vector) { | ||||
|             ss << std::setw(2) << static_cast<int>(byte); | ||||
|         } | ||||
|     return ss.str(); | ||||
| } | ||||
|   | ||||
| @@ -30,6 +30,7 @@ public: | ||||
|     std::vector<uint8_t> gst_to_uint8(uint32_t GST) const; | ||||
|     std::vector<uint8_t> bytes(const std::string& binaryString); | ||||
|     std::string verification_status_str(int status); | ||||
|     std::string convert_to_hex_string(const std::vector<uint8_t>& vector); | ||||
| }; | ||||
|  | ||||
| #endif  // GNSS_SDR_OSNMA_HELPER_H | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| #include <bitset> | ||||
| #include <filesystem> | ||||
| #include <fstream> | ||||
| #include <logging.h> | ||||
| #include <osnma_msg_receiver.h> | ||||
| #include <vector> | ||||
|  | ||||
| @@ -14,42 +15,39 @@ struct TestVector | ||||
| }; | ||||
|  | ||||
| // TODO - parametrize class for different configurations (config_1, config_2, etc.. potentially 5 or 6 more) an make sure wont affect current TEST_F | ||||
| // note: until the test is parametrized for configuration 1 and 2, in order to change between them you have to comment/uncomment the respective calls in this test, identified with comments // conf. 1/2 | ||||
| // log_name, input_time, crtFilePath, merkleFilePath, testVectors | ||||
| 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 | ||||
|     uint32_t d_GST_SIS{}; | ||||
|     uint32_t TOW{}; | ||||
|     uint32_t WN{}; | ||||
|     std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm | ||||
|     const uint32_t LEAP_SECONDS = 0; //13 + 5; | ||||
|     void set_time(std::tm& input); | ||||
|     //    std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; | ||||
| //    std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; | ||||
|     std::string log_name {"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; | ||||
|     // void initializeGoogleLog(); | ||||
|     void initializeGoogleLog(); | ||||
|  | ||||
|     void SetUp() override | ||||
|     { | ||||
|         flag_CRC_test = false;  // TODO what for? | ||||
|         page_even = ""; | ||||
|  | ||||
|         //        std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; | ||||
|         std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; | ||||
|         initializeGoogleLog(); | ||||
| //        std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 | ||||
|         std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 | ||||
|         set_time(input_time); | ||||
|         //        std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; | ||||
| //        std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.crt"; // conf. 1 | ||||
| //        std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; | ||||
|         std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.pem"; | ||||
|         std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 | ||||
|         std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; | ||||
|         osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); | ||||
|         osnma = osnma_msg_receiver_make(crtFilePath, 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); | ||||
| @@ -57,397 +55,6 @@ public: | ||||
| }; | ||||
|  | ||||
|  | ||||
| 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};  // Kroot, TOW 345570 GST_0 - 30 | ||||
|     osnma->d_osnma_data.d_dsm_kroot_message.ks = 4;                                                                                                    // TABLE 10 --> 128 bits | ||||
|     osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; | ||||
|     // local_time_verification would do this operation. TODO - eliminate duplication. | ||||
|     osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); | ||||
|     osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF));                                 // applicable time (GST_Kroot + 30) | ||||
|     osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30);  // Eq. 3 R.G.//345630; | ||||
|  | ||||
|     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})));  // K1, not needed, just for reference. | ||||
|     std::vector<uint8_t> key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB};                                                        // K2 | ||||
|     uint32_t TOW = 345630; | ||||
|  | ||||
|     // Act | ||||
|     // ---------- | ||||
|     bool result = osnma->verify_tesla_key(key, TOW); | ||||
|  | ||||
|     // Assert | ||||
|     // ---------- | ||||
|     ASSERT_TRUE(result); | ||||
| } | ||||
|  | ||||
|  | ||||
| TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) | ||||
| { | ||||
|     // initializeGoogleLog(); | ||||
|     // Arrange | ||||
|     // ---------- | ||||
|     //    std::vector<TestVector> testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); | ||||
|     std::vector<TestVector> testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); | ||||
|     if (testVectors.empty()) | ||||
|         { | ||||
|             ASSERT_TRUE(false); | ||||
|         } | ||||
|  | ||||
|     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};                                    // total bytes of a page | ||||
|     const int SIZE_SUBFRAME_PAGES{15};                                     // number of pages of a subframe | ||||
|     const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES * SIZE_SUBFRAME_PAGES};  // total bytes of a subframe | ||||
|     const int DURATION_SUBFRAME{30};                                       // duration of a subframe, in seconds | ||||
|  | ||||
|     const int DUMMY_PAGE{63}; | ||||
|     bool flag_dummy_page{false}; | ||||
|     std::cout << "OsnmaTestVectorsSimulation:" | ||||
|               << " d_GST_SIS= " << d_GST_SIS | ||||
|               << ", TOW=" << TOW | ||||
|               << ", WN=" << WN << std::endl; | ||||
|  | ||||
|  | ||||
|     // Act | ||||
|     // ---------- | ||||
|  | ||||
|     // loop over all bytes of data. Note: all TestVectors have same amount of data. | ||||
|     while (end_of_hex_stream == false) | ||||
|         { | ||||
|             // loop over all SVs, extract a subframe | ||||
|             for (const TestVector& tv : testVectors) | ||||
|                 {  // loop over all SVs, extract a subframe | ||||
|                     std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; | ||||
|                     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) | ||||
|                     std::map<uint8_t, std::bitset<128>> words;  // structure containing <WORD_NUMBER> and <EXTRACTED_BITS> | ||||
|  | ||||
|                     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<112> data_k(even_page.substr(2, 112)); | ||||
|                             std::bitset<16> data_j(odd_page.substr(2, 16)); | ||||
|                             std::bitset<112> shifted_data_k = data_k; | ||||
|                             //                            uint8_t word_type = 0; | ||||
|                             //                            for(int i = 0; i < 6; ++i) { | ||||
|                             //                                    word_type |= (data_k[104 + i] << i); | ||||
|                             //                                } | ||||
|                             uint8_t word_type = static_cast<uint8_t>((shifted_data_k >>= 106).to_ulong());  // word type is the first 6 bits of the word | ||||
|                             std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast<int>(word_type) << std::endl; | ||||
|                             if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) | ||||
|                                 { | ||||
|                                     // store raw word | ||||
|                                     std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); | ||||
|                                     words[word_type] = data_combined; | ||||
|                                 } | ||||
|                             if (word_type == DUMMY_PAGE) | ||||
|                                 flag_dummy_page = true; | ||||
|                             // place it into osnma object. | ||||
|                             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; | ||||
|                         } | ||||
|  | ||||
|                     std::cout << "----------" << std::endl; | ||||
|                     if (end_of_hex_stream) | ||||
|                         break; | ||||
|                     if (flag_dummy_page) | ||||
|                         { | ||||
|                             flag_dummy_page = false; | ||||
|                             continue;  // skip this SV | ||||
|                         } | ||||
|  | ||||
|                     // Fill osnma object | ||||
|                     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;  // PRNa | ||||
|  | ||||
|                     // TODO - refactor this logic, currently it is split | ||||
|  | ||||
|                     // check if words 1--> 5 words are received => fill EphClockStatus data vector | ||||
|                     bool ephClockStatusWordsReceived = true; | ||||
|                     for (int i = 1; i <= 5; ++i) | ||||
|                         { | ||||
|                             if (words.find(i) == words.end()) | ||||
|                                 { | ||||
|                                     ephClockStatusWordsReceived = false; | ||||
|                                     std::cerr << "OsnmaTestVectorsSimulation: error parsing words 1->5. " | ||||
|                                                  "Word " | ||||
|                                               << i << " should be received for each subframe but was not." << std::endl; | ||||
|                                 } | ||||
|                         } | ||||
|                     // extract bits as needed by osnma block | ||||
|                     if (ephClockStatusWordsReceived) | ||||
|                         { | ||||
|                             // Define the starting position and length of bits to extract for each word | ||||
|                             std::map<uint8_t, std::pair<uint8_t, uint8_t>> extractionParams = { | ||||
|                                 {1, {6, 120}}, | ||||
|                                 {2, {6, 120}}, | ||||
|                                 {3, {6, 122}}, | ||||
|                                 {4, {6, 120}}, | ||||
|                                 {5, {6, 67}}, | ||||
|                             }; | ||||
|  | ||||
|                             // Fill NavData bits -- Iterate over the extraction parameters                            // Fill NavData bits -- Iterate over the extraction parameters | ||||
|                             std::string nav_data_ADKD_0_12 = ""; | ||||
|                             for (const auto& param : extractionParams) | ||||
|                                 { | ||||
|                                     uint8_t wordKey = param.first; | ||||
|                                     uint8_t start = param.second.first; | ||||
|                                     uint8_t length = param.second.second; | ||||
|  | ||||
|                                     // Extract the required bits and fill osnma block | ||||
|                                     nav_data_ADKD_0_12 += words[wordKey].to_string().substr(start, length); | ||||
|                                 } | ||||
|                             // send to osnma block | ||||
|                             bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; | ||||
|                             if (check_size_is_ok) | ||||
|                                 { | ||||
|                                     std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " | ||||
|                                               << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; | ||||
|                                     const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string, uint32_t>>(  // < PRNd , navDataBits, TOW_Sosf> | ||||
|                                         tv.svId, | ||||
|                                         nav_data_ADKD_0_12, | ||||
|                                         osnmaMsg_sptr->TOW_sf0); | ||||
|                                     osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); | ||||
|                                 } | ||||
|                         } | ||||
|  | ||||
|                     // check w6 && w10 is received => fill TimingData data vector | ||||
|                     bool timingWordsReceived = words.find(6) != words.end() && | ||||
|                                                words.find(10) != words.end(); | ||||
|                     // extract bits as needed by osnma block | ||||
|                     if (timingWordsReceived) | ||||
|                         { | ||||
|                             // Define the starting position and length of bits to extract for each word | ||||
|                             std::map<uint8_t, std::pair<uint8_t, uint8_t>> extractionParams = { | ||||
|                                 {6, {6, 99}}, | ||||
|                                 {10, {86, 42}}}; | ||||
|  | ||||
|                             std::string nav_data_ADKD_4 = ""; | ||||
|                             // Fill NavData bits -- Iterate over the extraction parameters | ||||
|                             for (const auto& param : extractionParams) | ||||
|                                 { | ||||
|                                     uint8_t wordKey = param.first; | ||||
|                                     uint8_t start = param.second.first; | ||||
|                                     uint8_t length = param.second.second; | ||||
|  | ||||
|                                     // Extract the required bits and fill osnma block | ||||
|                                     nav_data_ADKD_4 += words[wordKey].to_string().substr( | ||||
|                                         start, length); | ||||
|                                 } | ||||
|  | ||||
|                             // send to osnma block | ||||
|                             bool check_size_is_ok = nav_data_ADKD_4.size() == 141; | ||||
|                             if (check_size_is_ok) | ||||
|                                 { | ||||
|                                     std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " | ||||
|                                               << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; | ||||
|                                     const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string, uint32_t>>(  // < PRNd , navDataBits, TOW_Sosf> | ||||
|                                         tv.svId, | ||||
|                                         nav_data_ADKD_4, | ||||
|                                         osnmaMsg_sptr->TOW_sf0); | ||||
|                                     osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); | ||||
|                                 } | ||||
|                         } | ||||
|  | ||||
|                     // Call the handler, as if it came from telemetry decoder block | ||||
|                     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; | ||||
|                     TOW = d_GST_SIS & 0x000FFFFF; | ||||
|                     WN = (d_GST_SIS & 0xFFF00000) >> 20; | ||||
|                     std::cout << "OsnmaTestVectorsSimulation:" | ||||
|                               << " d_GST_SIS= " << d_GST_SIS | ||||
|                               << ", TOW=" << TOW | ||||
|                               << ", WN=" << WN << std::endl; | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|  | ||||
|     // Assert | ||||
|     // ---------- | ||||
|  | ||||
|     // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) | ||||
| } | ||||
|  | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * @brief Extracts a range of bytes from a TestVector's navBits vector. | ||||
|  * | ||||
|  * This function extracts a extracts the bytes of complete page (odd+even) | ||||
|  * from the navBits vector of a TestVector object. | ||||
|  * | ||||
|  * | ||||
|  * @param tv The TestVector object from which to extract bytes. | ||||
|  * @param byte_index The index of the first byte to extract. | ||||
|  * @param num_bytes The number of bytes to extract. | ||||
|  * @return A vector containing the extracted bytes, or an empty vector if extraction is not possible. | ||||
|  */ | ||||
| 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; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * @brief Sets the time based on the given input. | ||||
|  * | ||||
|  * This function calculates the week number (WN) and time of week (TOW) | ||||
|  * based on the input time and the GST_START_EPOCH. It then stores the | ||||
|  * calculated values in the WN and TOW member variables. Finally, it | ||||
|  * combines the WN and TOW into a single 32-bit value and stores it in | ||||
|  * the d_GST_SIS member variable. | ||||
|  * | ||||
|  * @param input The input time as a tm struct. | ||||
|  */ | ||||
| void OsnmaMsgReceiverTest::set_time(std::tm& input) | ||||
| { | ||||
|     auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_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 + LEAP_SECONDS; | ||||
|     // Return the week number and time of week as a pair | ||||
|  | ||||
|     // TODO: d_GST_SIS or d_receiver_time? doubt | ||||
|     // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 | ||||
|     this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); | ||||
| } | ||||
|  | ||||
|  | ||||
| TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) | ||||
| { | ||||
|     // Arrange | ||||
| @@ -458,7 +65,8 @@ TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) | ||||
|         0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, | ||||
|         0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, | ||||
|         0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, | ||||
|         0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00}; | ||||
|         0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 | ||||
|     }; | ||||
|  | ||||
|     uint32_t TOW_Tag0 = 345660; | ||||
|     uint32_t TOW_NavData = TOW_Tag0 - 30; | ||||
| @@ -481,6 +89,7 @@ TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) | ||||
|     Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); | ||||
|  | ||||
|  | ||||
|  | ||||
|     // Act | ||||
|     // ---------- | ||||
|     auto computed_message = osnma->build_message(t0); | ||||
| @@ -489,11 +98,10 @@ TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) | ||||
|     // Assert | ||||
|     // ---------- | ||||
|     ASSERT_TRUE(computed_message == expected_message); | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| TEST_F(OsnmaMsgReceiverTest, TagVerification) | ||||
| { | ||||
| TEST_F(OsnmaMsgReceiverTest, TagVerification) { | ||||
|     // Arrange | ||||
|     // ---------- | ||||
|     // Tag0 | ||||
| @@ -518,11 +126,15 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) | ||||
|     Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); | ||||
|  | ||||
|  | ||||
|  | ||||
|     // Act | ||||
|     // ---------- | ||||
|     bool result_tag0 = osnma->verify_tag(t0); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     // Assert | ||||
|     // ---------- | ||||
|     //ASSERT_TRUE(result_tag0); | ||||
| @@ -552,4 +164,427 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) | ||||
|     bool result_tag3 = osnma->verify_tag(t3); | ||||
|  | ||||
|     ASSERT_TRUE(result_tag0 && result_tag3); | ||||
|  | ||||
| } | ||||
|  | ||||
| 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}; // Kroot, TOW 345570 GST_0 - 30 | ||||
|     osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits | ||||
|     osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; | ||||
|     // local_time_verification would do this operation. TODO - eliminate duplication. | ||||
|     osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); | ||||
|     osnma->d_GST_0 = ((1248  & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) | ||||
|     osnma->d_receiver_time =  osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; | ||||
|  | ||||
|     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}))); // K1, not needed, just for reference. | ||||
|     std::vector<uint8_t> key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 | ||||
|     uint32_t TOW = 345630; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     // Act | ||||
|     // ---------- | ||||
|     bool result = osnma->verify_tesla_key(key, TOW); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     // Assert | ||||
|     // ---------- | ||||
|     ASSERT_TRUE(result); | ||||
|  | ||||
| } | ||||
|  | ||||
| TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) | ||||
| { | ||||
|     // Arrange | ||||
|     // ---------- | ||||
| //    std::vector<TestVector> testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); // conf. 1 | ||||
|     std::vector<TestVector> testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 | ||||
|     if (testVectors.empty()){ | ||||
|             ASSERT_TRUE(false); | ||||
|         } | ||||
|  | ||||
|     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}; // total bytes of a page | ||||
|     const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe | ||||
|     const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; // total bytes of a subframe | ||||
|     const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds | ||||
|  | ||||
|     const int DUMMY_PAGE{63}; | ||||
|     bool flag_dummy_page{false}; | ||||
|     std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS | ||||
|     << ", TOW=" << TOW | ||||
|     << ", WN=" << WN << std::endl; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     // Act | ||||
|     // ---------- | ||||
|  | ||||
|     // loop over all bytes of data. Note: all TestVectors have same amount of data. | ||||
|     while (end_of_hex_stream == false){ | ||||
|             // loop over all SVs, extract a subframe | ||||
|             for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe | ||||
|                     std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; | ||||
|                     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) | ||||
|                     std::map<uint8_t, std::bitset<128>> words_for_OSNMA; // structure containing <WORD_NUMBER> and <EXTRACTED_BITS> | ||||
|  | ||||
|                     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<112> data_k(even_page.substr(2,112)); | ||||
|                             std::bitset<16> data_j(odd_page.substr(2,16)); | ||||
|                             std::bitset<112> shifted_data_k = data_k; | ||||
|                             uint8_t word_type = static_cast<uint8_t>((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word | ||||
|                             std::cout<< "OsnmaTestVectorsSimulation: received Word "<< static_cast<int>(word_type) << std::endl; | ||||
|                             if( (word_type >= 1 && word_type <=5) || word_type == 6 || word_type == 10) | ||||
|                                 { | ||||
|                                     // store raw word | ||||
|                                     std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); | ||||
|                                     words_for_OSNMA[word_type] = data_combined; | ||||
|                                 } | ||||
|                             if(word_type == DUMMY_PAGE) | ||||
|                                 flag_dummy_page = true; | ||||
|  | ||||
|                             // place it into osnma object. | ||||
|                             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; | ||||
|                         } | ||||
|  | ||||
|                     std::cout<< "----------" << std::endl; | ||||
|                     if(end_of_hex_stream) | ||||
|                         break; | ||||
|                     if(flag_dummy_page){ | ||||
|                             flag_dummy_page = false; | ||||
|                             continue; // skip this SV | ||||
|                         } | ||||
|  | ||||
|                     // Fill osnma object | ||||
|                     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; // PRNa | ||||
|  | ||||
|                     // TODO - refactor this logic, currently it is split | ||||
|  | ||||
|                     // check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector | ||||
|                     bool ephClockStatusWordsReceived = true; | ||||
|                     for (int i = 1; i <= 5; ++i) | ||||
|                         { | ||||
|                             if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) | ||||
|                                 { | ||||
|                                     ephClockStatusWordsReceived = false; | ||||
|                                     std::cerr<< "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " | ||||
|                                                  "Word "<< i << " should be received for each subframe but was not." << std::endl; | ||||
|                                 } | ||||
|                         } | ||||
|                     // extract bits as needed by osnma block | ||||
|                     if(ephClockStatusWordsReceived) | ||||
|                         { | ||||
|  | ||||
|                             // Define the starting position and length of bits to extract for each word | ||||
|                             std::map<uint8_t, std::pair<uint8_t, uint8_t>> extractionParams = { | ||||
|                                 {1, {6, 120}}, | ||||
|                                 {2, {6, 120}}, | ||||
|                                 {3, {6, 122}}, | ||||
|                                 {4, {6, 120}}, | ||||
|                                 {5, {6, 67}}, | ||||
|                             }; | ||||
|  | ||||
|                             // Fill NavData bits -- Iterate over the extraction parameters | ||||
|                             std::string nav_data_ADKD_0_12 = ""; | ||||
|                             for (const auto& param : extractionParams) { | ||||
|                                     uint8_t wordKey = param.first; | ||||
|                                     uint8_t start = param.second.first; | ||||
|                                     uint8_t length = param.second.second; | ||||
|  | ||||
|                                     // Extract the required bits and fill osnma block | ||||
|                                     nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length); | ||||
|                                 } | ||||
|                             // send to osnma block | ||||
|                             bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; | ||||
|                             if(check_size_is_ok) | ||||
|                                 { | ||||
|                                     std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <<std::endl; | ||||
|                                     const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string,uint32_t>>( // < PRNd , navDataBits, TOW_Sosf> | ||||
|                                         tv.svId, | ||||
|                                         nav_data_ADKD_0_12, | ||||
|                                         osnmaMsg_sptr->TOW_sf0); | ||||
|                                     LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast<int>(tv.svId) << ", TOW=" << static_cast<int>(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_0_12; | ||||
|                                     osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); | ||||
|  | ||||
|                                 } | ||||
|                         } | ||||
|  | ||||
|                     // check w6 && w10 is received => fill TimingData data vector | ||||
|                     bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && | ||||
|                                                words_for_OSNMA.find(10) != words_for_OSNMA.end(); | ||||
|                     // extract bits as needed by osnma block | ||||
|                     if(timingWordsReceived){ | ||||
|                             // Define the starting position and length of bits to extract for each word | ||||
|                             std::map<uint8_t, std::pair<uint8_t, uint8_t>> extractionParams = { | ||||
|                                 {6, {6, 99}}, | ||||
|                                 {10, {86, 42}} | ||||
|                             }; | ||||
|  | ||||
|                             std::string nav_data_ADKD_4 = ""; | ||||
|                             // Fill NavData bits -- Iterate over the extraction parameters | ||||
|                             for (const auto& param : extractionParams) | ||||
|                                 { | ||||
|                                     uint8_t wordKey = param.first; | ||||
|                                     uint8_t start = param.second.first; | ||||
|                                     uint8_t length = param.second.second; | ||||
|  | ||||
|                                     // Extract the required bits and fill osnma block | ||||
|                                     nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length); | ||||
|                                 } | ||||
|                             // send to osnma block | ||||
|                             bool check_size_is_ok = nav_data_ADKD_4.size() == 141; | ||||
|                             if(check_size_is_ok) | ||||
|                                 { | ||||
|                                     std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <<std::endl; | ||||
|                                     const auto tmp_obj_osnma = std::make_shared<std::tuple<uint32_t, std::string,uint32_t>>( // < PRNd , navDataBits, TOW_Sosf> | ||||
|                                         tv.svId, | ||||
|                                         nav_data_ADKD_4, | ||||
|                                         osnmaMsg_sptr->TOW_sf0); | ||||
|                                     LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast<int>(tv.svId) << ", TOW=" << static_cast<int>(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_4; | ||||
|                                     osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); | ||||
|  | ||||
|                                 } | ||||
|  | ||||
|                         } | ||||
|  | ||||
|                     // Call the handler, as if it came from telemetry decoder block | ||||
|                     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; | ||||
|                     TOW = d_GST_SIS & 0x000FFFFF; | ||||
|                     WN = (d_GST_SIS & 0xFFF00000) >> 20 ; | ||||
|                     std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS | ||||
|                               << ", TOW=" << TOW | ||||
|                               << ", WN=" << WN << std::endl; | ||||
|                 } | ||||
|  | ||||
|  | ||||
|         } | ||||
|  | ||||
|  | ||||
|     // Assert | ||||
|     // ---------- | ||||
|  | ||||
|     // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) | ||||
| } | ||||
|  | ||||
| // Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. | ||||
| // Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. | ||||
| 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; | ||||
| } | ||||
| /** | ||||
|  * @brief Extracts a range of bytes from a TestVector's navBits vector. | ||||
|  * | ||||
|  * This function extracts a extracts the bytes of complete page (odd+even) | ||||
|  * from the navBits vector of a TestVector object. | ||||
|  * | ||||
|  * | ||||
|  * @param tv The TestVector object from which to extract bytes. | ||||
|  * @param byte_index The index of the first byte to extract. | ||||
|  * @param num_bytes The number of bytes to extract. | ||||
|  * @return A vector containing the extracted bytes, or an empty vector if extraction is not possible. | ||||
|  */ | ||||
| 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; | ||||
| } | ||||
| /** | ||||
|  * @brief Sets the time based on the given input. | ||||
|  * | ||||
|  * This function calculates the week number (WN) and time of week (TOW) | ||||
|  * based on the input time and the GST_START_EPOCH. It then stores the | ||||
|  * calculated values in the WN and TOW member variables. Finally, it | ||||
|  * combines the WN and TOW into a single 32-bit value and stores it in | ||||
|  * the d_GST_SIS member variable. | ||||
|  * | ||||
|  * @param input The input time as a tm struct. | ||||
|  */ | ||||
| void OsnmaMsgReceiverTest::set_time(std::tm& input) | ||||
| { | ||||
|     auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_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 + LEAP_SECONDS; | ||||
|     // Return the week number and time of week as a pair | ||||
|  | ||||
|     // TODO: d_GST_SIS or d_receiver_time? doubt | ||||
|     // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 | ||||
|     this->d_GST_SIS =  (this->WN  & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); | ||||
|  | ||||
|  | ||||
| } | ||||
| void OsnmaMsgReceiverTest::initializeGoogleLog() | ||||
| { | ||||
|     google::InitGoogleLogging(log_name.c_str()); | ||||
|     FLAGS_minloglevel = 0; // INFO | ||||
|     FLAGS_logtostderr = 0;  // add this line | ||||
|     FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; | ||||
|     if (FLAGS_log_dir.empty()) | ||||
|         { | ||||
|             std::cout << "Logging will be written at " | ||||
|                       << std::filesystem::temp_directory_path() | ||||
|                       << '\n' | ||||
|                       << "Use gnss-sdr --log_dir=/path/to/log to change that.\n"; | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             try | ||||
|                 { | ||||
|                     const std::filesystem::path p(FLAGS_log_dir); | ||||
|                     if (!std::filesystem::exists(p)) | ||||
|                         { | ||||
|                             std::cout << "The path " | ||||
|                                       << FLAGS_log_dir | ||||
|                                       << " does not exist, attempting to create it.\n"; | ||||
|                             std::error_code ec; | ||||
|                             if (!std::filesystem::create_directory(p, ec)) | ||||
|                                 { | ||||
|                                     std::cout << "Could not create the " << FLAGS_log_dir << " folder.\n"; | ||||
|                                     gflags::ShutDownCommandLineFlags(); | ||||
|                                     throw std::runtime_error("Could not create folder for logs"); | ||||
|                                 } | ||||
|                         } | ||||
|                     std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; | ||||
|                 } | ||||
|             catch (const std::exception& e) | ||||
|                 { | ||||
|                     std::cerr << e.what() << '\n'; | ||||
|                     std::cerr << "Could not create the " << FLAGS_log_dir << " folder.\n"; | ||||
|                     gflags::ShutDownCommandLineFlags(); | ||||
|                     throw; | ||||
|                 } | ||||
|         } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 cesaaargm
					cesaaargm