mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-31 15:23:04 +00:00 
			
		
		
		
	[TAS-153] Re-design time check requirement
[TAS-140] Tag verification: accumulation tags of PRNd and ADKD for T_COP This update introduces updated time verification functions and DSM block processes. TAS-140 introduces work (in progress) for taking into account the COP when validating tags. This accounts for significant structural changes in process_mack_message(). The update also resolves several TODO comments and includes minor adjustments to unit tests and system parameters.
This commit is contained in:
		| @@ -59,7 +59,8 @@ osnma_msg_receiver::osnma_msg_receiver( | |||||||
| { | { | ||||||
|     d_dsm_reader = std::make_unique<OSNMA_DSM_Reader>(); |     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>(pemFilePath, merkleFilePath); | ||||||
|     d_old_mack_message.set_capacity(10); |     //d_old_mack_message.set_capacity(10); | ||||||
|  |     d_old_OSNMA_buffer.set_capacity(12); | ||||||
|     //  register OSNMA input message port from telemetry blocks |     //  register OSNMA input message port from telemetry blocks | ||||||
|     this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); |     this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); | ||||||
|     // register OSNMA output message port to PVT block |     // register OSNMA output message port to PVT block | ||||||
| @@ -144,7 +145,7 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>& | |||||||
|     read_dsm_block(osnma_msg); |     read_dsm_block(osnma_msg); | ||||||
|     local_time_verification(osnma_msg); |     local_time_verification(osnma_msg); | ||||||
|     process_dsm_block(osnma_msg); |     process_dsm_block(osnma_msg); | ||||||
|     read_mack_block(osnma_msg); |     read_and_process_mack_block(osnma_msg); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -263,6 +264,11 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_ | |||||||
|     std::cout << "]" << std::endl; // TODO update documentation |     std::cout << "]" << std::endl; // TODO update documentation | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief Function to verify the local time based on GST_SIS and GST_0 | ||||||
|  |  * | ||||||
|  |  * @param osnma_msg Shared pointer to OSNMA message structure | ||||||
|  |  */ | ||||||
| void osnma_msg_receiver::local_time_verification(const std::shared_ptr<OSNMA_msg>& osnma_msg) | void osnma_msg_receiver::local_time_verification(const std::shared_ptr<OSNMA_msg>& osnma_msg) | ||||||
| { | { | ||||||
|     // compute local time based on GST_SIS and GST_0 |     // compute local time based on GST_SIS and GST_0 | ||||||
| @@ -283,18 +289,47 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr<OSNMA_msg | |||||||
|             std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; |             std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; | ||||||
|         } |         } | ||||||
|     // verify time constraint |     // verify time constraint | ||||||
|     if( abs(d_receiver_time - d_GST_SIS) > d_T_L) |     std::time_t delta_T = abs(d_receiver_time - d_GST_SIS); | ||||||
|  |     if(  delta_T <= d_T_L ) | ||||||
|         { |         { | ||||||
|             std::cerr << "Galileo OSNMA: time constraint violation" << std::endl; |             d_tags_allowed = tags_to_verify::all; | ||||||
|             std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << std::endl; |             d_tags_to_verify = {0,4,12}; | ||||||
|  |             std::cout << "Galileo OSNMA: time constraint OK \n"; | ||||||
|  |             std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; | ||||||
|  |             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 messagesy | ||||||
|  |         } | ||||||
|  |     else if( delta_T > d_T_L && delta_T <= 10* delta_T  ) | ||||||
|  |         { | ||||||
|  |             d_tags_allowed = tags_to_verify::slow_eph; | ||||||
|  |             d_tags_to_verify = {12}; | ||||||
|  |             std::cout << "Galileo OSNMA: time constraint allows only slow MACs to be verified\n"; | ||||||
|  |             std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; | ||||||
|  |             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; | ||||||
|  |  | ||||||
|         } |         } | ||||||
|     else |     else | ||||||
|         std::cout << "Galileo OSNMA: time constraint OK (|local_t - GST_SIS| < T_L) [|"<< static_cast<int>(d_receiver_time - d_GST_SIS) |         { | ||||||
|                   <<"|<"<< static_cast<int>(d_T_L) <<"]"<< std::endl; |             d_tags_allowed = tags_to_verify::none; | ||||||
|         // TODO set flag to false to avoid processing dsm and MACK messages |             d_tags_to_verify = {}; | ||||||
|     // set global variables accordingly |             std::cerr << "Galileo OSNMA: time constraint violation\n"; | ||||||
|  |             std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; | ||||||
|  |             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; | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief Process DSM block of an OSNMA message. | ||||||
|  |  * | ||||||
|  |  * \details This function checks if all inner blocks of the DSM message are available and if so, calls process_dsm_message(). | ||||||
|  |  * \post It creates a vector to hold the DSM message data, copies the data from the inner blocks into the vector, | ||||||
|  |  * resets the inner block arrays to empty | ||||||
|  |  * | ||||||
|  |  * @param osnma_msg The OSNMA message. | ||||||
|  |  */ | ||||||
| void osnma_msg_receiver::process_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg) | void osnma_msg_receiver::process_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg) | ||||||
| { | { | ||||||
|     // if all inner blocks available -> Process DSM message |     // if all inner blocks available -> Process DSM message | ||||||
| @@ -522,7 +557,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg | |||||||
|  * |  * | ||||||
|  * @param osnma_msg The OSNMA_msg object containing the Mack message. |  * @param osnma_msg The OSNMA_msg object containing the Mack message. | ||||||
|  */ |  */ | ||||||
| void osnma_msg_receiver::read_mack_block(const std::shared_ptr<OSNMA_msg>& osnma_msg) | void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr<OSNMA_msg>& osnma_msg) | ||||||
| { | { | ||||||
|     // Retrieve Mack message |     // Retrieve Mack message | ||||||
|     uint32_t index = 0; |     uint32_t index = 0; | ||||||
| @@ -537,7 +572,6 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr<OSNMA_msg>& osnma | |||||||
|  |  | ||||||
|     if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts <  ts < 10 |     if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts <  ts < 10 | ||||||
|         { |         { | ||||||
|             d_GST_Sf = d_receiver_time; // TODO needed? |  | ||||||
|             read_mack_header(); |             read_mack_header(); | ||||||
|             read_mack_body(); |             read_mack_body(); | ||||||
|             process_mack_message(osnma_msg); |             process_mack_message(osnma_msg); | ||||||
| @@ -551,7 +585,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr<OSNMA_msg>& osnma | |||||||
|  * \brief Reads the MACk header from the d_mack_message array and updates the d_osnma_data structure. |  * \brief Reads the MACk header from the d_mack_message array and updates the d_osnma_data structure. | ||||||
|  * \details This function reads the message MACK header from the d_mack_message array and updates the d_osnma_data structure with the parsed data. The header consists of three fields |  * \details This function reads the message MACK header from the d_mack_message array and updates the d_osnma_data structure with the parsed data. The header consists of three fields | ||||||
| *: tag0, macseq, and cop. The size of the fields is determined by the number of tag length (lt) bits specified in OSNMA_TABLE_11 for the corresponding tag size in d_osnma_data.d_dsm_k | *: tag0, macseq, and cop. The size of the fields is determined by the number of tag length (lt) bits specified in OSNMA_TABLE_11 for the corresponding tag size in d_osnma_data.d_dsm_k | ||||||
| *root_message.ts. The lt_bits value is used to calculate the values of tag0, macseq, and cop based on the lt_bits value and the values of the elements of d_mack_message array. | *root_message.ts. The lt_bits value is used to calculate tag0, MACSEQ, and COP. | ||||||
|  * \pre The d_mack_message array and d_osnma_data.d_dsm_kroot_message.ts field must be properly populated. |  * \pre The d_mack_message array and d_osnma_data.d_dsm_kroot_message.ts field must be properly populated. | ||||||
|  * \post The d_osnma_data.d_mack_message.header.tag0, d_osnma_data.d_mack_message.header.macseq, and d_osnma_data.d_mack_message.header.cop fields are updated with the parsed values |  * \post The d_osnma_data.d_mack_message.header.tag0, d_osnma_data.d_mack_message.header.macseq, and d_osnma_data.d_mack_message.header.cop fields are updated with the parsed values | ||||||
| *. | *. | ||||||
| @@ -619,10 +653,10 @@ void osnma_msg_receiver::read_mack_header() | |||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @brief Reads the message body and verify Tesla key |  * @brief Reads the MACK message body | ||||||
|  * |  * | ||||||
|  * \details It retrieves all the tags and tag-info associated, as well as the TESLA key. |  * \details It retrieves all the tags and tag-info associated, as well as the TESLA key. | ||||||
|  * |  * \post populates d_osnma_data.d_mack_message with all tags and tag_info associated of MACK message, as well as the TESLA key into d_osnma_data.d_mack_message.key | ||||||
|  * @return None |  * @return None | ||||||
|  */ |  */ | ||||||
| void osnma_msg_receiver::read_mack_body() | void osnma_msg_receiver::read_mack_body() | ||||||
| @@ -802,124 +836,131 @@ void osnma_msg_receiver::read_mack_body() | |||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @brief Verifies the tags. |  * @brief Verifies the tags transmitted in the past. | ||||||
|  * |  * | ||||||
|  * \details This function is responsible for processing the MACK message received (480 bits). It stores the last 10 MACK |  * \details This function is responsible for processing the MACK message received (480 bits) at time SF(i). | ||||||
|  * messages and last 10 NavData messages.  * Then it attempts to verify the Tesla Key by computing the |  * It stores the last 10 MACK messages and the last 11 NavData messages. | ||||||
|  * number of hashes of distance between the key-to-verify and the Kroot and iteratively hashing the result, until the required number of hashes |  * Then attempts to verify the Tesla Key by computing the number of hashes of distance between the key-to-verify and the | ||||||
|  * is achieved. The result is then compared with the Kroot. If the two values match, the Tesla key is verified. |  * Kroot and iteratively hashing the result, until the required number of hashes is achieved. | ||||||
|  *  It also performs MACSEQ validation and compares the ADKD of Mack tags with MACLT defined ADKDs. Finally, it verifies the tags. |  * The result is then compared with the Kroot. If the two values match, the Tesla key is verified. | ||||||
|  * \pre Kroot or already a TESLA key shall be available. |  *  It also performs MACSEQ validation and compares the ADKD of Mack tags with MACLT defined ADKDs. | ||||||
|  |  *  Finally, it verifies the tags. | ||||||
|  |  * \pre Kroot or already a TESLA key shall be available. Depending on the ADKD of the tag, NavData of SF(i-2)...SF(i-11) | ||||||
|  * \post Number of tags bits verified for each ADKD. MACSEQ verification success |  * \post Number of tags bits verified for each ADKD. MACSEQ verification success | ||||||
|  * @param osnma_msg A reference to OSNMA_msg containing the MACK message to be processed. |  * @param osnma_msg A reference to OSNMA_msg containing the MACK message to be processed. | ||||||
|  */ |  */ | ||||||
| void osnma_msg_receiver::process_mack_message(const std::shared_ptr<OSNMA_msg>& osnma_msg) | void osnma_msg_receiver::process_mack_message(const std::shared_ptr<OSNMA_msg>& osnma_msg) | ||||||
| { | { | ||||||
|     // prepare needed data |     // populate d_nav_data with needed data from subframe | ||||||
|     d_old_mack_message.push_back(d_osnma_data.d_mack_message); // last 10 MACKs are needed to be stored as per ICD |     d_osnma_data.d_nav_data.init(osnma_msg); | ||||||
|     // populate d_nav_data with three classes of osnma_msg - needed for the tag verification |     // store MACK, KROOT and NavData needed. | ||||||
|     d_osnma_data.d_nav_data.EphemerisData = osnma_msg->EphemerisData; |     d_old_OSNMA_buffer.push_back(d_osnma_data); | ||||||
|     d_osnma_data.d_nav_data.IonoData = osnma_msg->IonoData; |  | ||||||
|     d_osnma_data.d_nav_data.UtcData = osnma_msg->UtcModelData; |  | ||||||
|     d_osnma_data.d_nav_data.generate_eph_iono_vector2(); |  | ||||||
|     d_osnma_data.d_nav_data.generate_utc_vector(); |  | ||||||
|     d_old_navdata_buffer.push_back(d_osnma_data.d_nav_data); // last 10 NavData messages are needed to be stored as per ICD |  | ||||||
|  |  | ||||||
|     if(d_kroot_verified == false && d_tesla_key_verified == false) |     if(d_kroot_verified == false && d_tesla_key_verified == false) | ||||||
|         { |         { | ||||||
|             std::cout << "Galileo OSNMA: MACK cannot be processed. "<< ", " |             std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " | ||||||
|                      << "No Kroot  nor TESLA key available" << static_cast<uint32_t>(d_osnma_data.d_nma_header.cid) << std::endl; |                      << "No Kroot nor TESLA key available" << static_cast<uint32_t>(d_osnma_data.d_nma_header.cid) << std::endl; | ||||||
|             return; // early return, cannot proceed further without one of the two verified. |             return; // early return, cannot proceed further without one of the two verified. | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     // Verify tesla key |     // Verify tesla key | ||||||
|  |     if(d_tesla_key_verified) | ||||||
|     // compute I: number of hashes required - Eq. 19 ICD |  | ||||||
|     // TODO - this assumes that the baseline is Kroot, but there is the following possibility: |  | ||||||
|     // - available K verified from another iteration, hence is nonsense to go back to the Kroot, when I could perform only, say, two hashes. |  | ||||||
|     uint8_t num_of_hashes_needed = (d_GST_Sf - d_GST_0) / 30 + 1; |  | ||||||
|     uint32_t GST_SFi = d_receiver_time; |  | ||||||
|     std::vector<uint8_t> K_II = d_osnma_data.d_mack_message.key; |  | ||||||
|     std::vector<uint8_t> K_I; // result of the recursive hash operations |  | ||||||
|     const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; |  | ||||||
|     // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) |  | ||||||
|     for (uint8_t i = 1; i < num_of_hashes_needed ; i++) |  | ||||||
|         { |         { | ||||||
|             // build message digest m = (K_I+1 || GST_SFi || alpha) |             // TODO - find out I bt. both tesla keys, then hash until then, then compare. | ||||||
|             std::vector<uint8_t> msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); |  | ||||||
|             std::copy(K_II.begin(),K_II.end(),msg.begin()); |  | ||||||
|  |  | ||||||
|             msg.push_back((d_GST_Sf & 0xFF000000) >> 24); |  | ||||||
|             msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); |  | ||||||
|             msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); |  | ||||||
|             msg.push_back(d_GST_Sf & 0x000000FF); |  | ||||||
|             // extract alpha |  | ||||||
|             for (int k = 5; k >= 0;k--) |  | ||||||
|                 { |  | ||||||
|                     // TODO: static extracts the MSB in case from larger to shorter int? |  | ||||||
|                     msg.push_back(static_cast<uint8_t>((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. |  | ||||||
|                 } |  | ||||||
|             // compute hash |  | ||||||
|             std::vector<uint8_t> hash; |  | ||||||
|             if (d_osnma_data.d_dsm_kroot_message.hf == 0)  // Table 8. |  | ||||||
|                 { |  | ||||||
|                     hash = d_crypto->computeSHA256(msg); |  | ||||||
|                 } |  | ||||||
|             else if (d_osnma_data.d_dsm_kroot_message.hf == 2) |  | ||||||
|                 { |  | ||||||
|                     hash = d_crypto->computeSHA3_256(msg); |  | ||||||
|                 } |  | ||||||
|             else |  | ||||||
|                 { |  | ||||||
|                     hash = std::vector<uint8_t>(32); |  | ||||||
|                 } |  | ||||||
|             // truncate hash |  | ||||||
|             K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits |  | ||||||
|             for (uint16_t i = 0; i < lk_bytes; i++) |  | ||||||
|                 { |  | ||||||
|                     K_I.push_back(hash[i]); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             // set parameters for next iteration |  | ||||||
|             GST_SFi -= 30; // next SF time is the actual minus 30 seconds |  | ||||||
|             K_II = K_I; // next key is the actual one |  | ||||||
|             K_I.clear(); // empty the actual one for a new computation |  | ||||||
|         } |  | ||||||
|     // compare computed current key against received key |  | ||||||
|     if(K_II.size() != d_osnma_data.d_mack_message.key.size()) |  | ||||||
|         { |  | ||||||
|             std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; |  | ||||||
|         } |  | ||||||
|     if (K_II == d_osnma_data.d_mack_message.key) |  | ||||||
|         { |  | ||||||
|             std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; |  | ||||||
|             // TODO - propagate result |  | ||||||
|             // TODO - save current tesla key as latest one? |  | ||||||
|             // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence |  | ||||||
|         } |         } | ||||||
|     else |     else | ||||||
|  |         {// have to go until Kroot | ||||||
|  |             uint8_t num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD | ||||||
|  |             uint32_t GST_SFi = d_receiver_time; | ||||||
|  |             std::vector<uint8_t> K_II = d_osnma_data.d_mack_message.key; | ||||||
|  |             std::vector<uint8_t> K_I; // result of the recursive hash operations | ||||||
|  |             const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; | ||||||
|  |             // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) | ||||||
|  |             for (uint8_t i = 1; i < num_of_hashes_needed ; i++) | ||||||
|  |                 { | ||||||
|  |                     // build message digest m = (K_I+1 || GST_SFi || alpha) | ||||||
|  |                     std::vector<uint8_t> msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); | ||||||
|  |                     std::copy(K_II.begin(),K_II.end(),msg.begin()); | ||||||
|  |  | ||||||
|         { |                     msg.push_back((d_GST_Sf & 0xFF000000) >> 24); | ||||||
|             std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; |                     msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); | ||||||
|  |                     msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); | ||||||
|  |                     msg.push_back(d_GST_Sf & 0x000000FF); | ||||||
|  |                     // extract alpha | ||||||
|  |                     for (int k = 5; k >= 0;k--) | ||||||
|  |                         { | ||||||
|  |                             // TODO: static extracts the MSB in case from larger to shorter int? | ||||||
|  |                             msg.push_back(static_cast<uint8_t>((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. | ||||||
|  |                         } | ||||||
|  |                     // compute hash | ||||||
|  |                     std::vector<uint8_t> hash; | ||||||
|  |                     if (d_osnma_data.d_dsm_kroot_message.hf == 0)  // Table 8. | ||||||
|  |                         { | ||||||
|  |                             hash = d_crypto->computeSHA256(msg); | ||||||
|  |                         } | ||||||
|  |                     else if (d_osnma_data.d_dsm_kroot_message.hf == 2) | ||||||
|  |                         { | ||||||
|  |                             hash = d_crypto->computeSHA3_256(msg); | ||||||
|  |                         } | ||||||
|  |                     else | ||||||
|  |                         { | ||||||
|  |                             hash = std::vector<uint8_t>(32); | ||||||
|  |                         } | ||||||
|  |                     // truncate hash | ||||||
|  |                     K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits | ||||||
|  |                     for (uint16_t i = 0; i < lk_bytes; i++) | ||||||
|  |                         { | ||||||
|  |                             K_I.push_back(hash[i]); | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                     // set parameters for next iteration | ||||||
|  |                     GST_SFi -= 30; // next SF time is the actual minus 30 seconds | ||||||
|  |                     K_II = K_I; // next key is the actual one | ||||||
|  |                     K_I.clear(); // empty the actual one for a new computation | ||||||
|  |                 } | ||||||
|  |             // compare computed current key against received key | ||||||
|  |             if(K_II.size() != d_osnma_data.d_mack_message.key.size()) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             if (K_II == d_osnma_data.d_mack_message.key) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; | ||||||
|  |                     d_tesla_key_verified = true; | ||||||
|  |                     // TODO - propagate result | ||||||
|  |                     // TODO - save current tesla key as latest one? propose a map with <GST_Sf, TeslaKey> | ||||||
|  |                     // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence | ||||||
|  |                 } | ||||||
|  |             else | ||||||
|  |  | ||||||
|  |                 { | ||||||
|  |                     std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|     // verify MACK tags - MACSEQ |     // verify MACK tags - MACSEQ | ||||||
|     uint8_t msg {0}; |  | ||||||
| //    uint8_t nt {0}; |  | ||||||
|     std::vector<std::string> sq1{}; |     std::vector<std::string> sq1{}; | ||||||
|     std::vector<std::string> sq2{}; |     std::vector<std::string> sq2{}; | ||||||
|     const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); |  | ||||||
|  |     // for OSNMA data (MACK, KROOT messages): | ||||||
|  |     // if ADKD=12, pick d_old_OSNMA_buffer.front() or d_old_OSNMA_buffer[1] iff d_old_OSNMA_buffer is full (guaranteed 10 SF above) | ||||||
|  |     // otherwise pick d_old_OSNMA_buffer[size-2] | ||||||
|  |     OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe | ||||||
|  |     d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ | ||||||
|  |  | ||||||
|  |     // for the applicable tesla key: | ||||||
|  |     // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] | ||||||
|  |     std::vector<uint8_t> applicable_key =  d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key | ||||||
|  |  | ||||||
|  |     const auto it = OSNMA_TABLE_16.find(applicable_OSNMA.d_dsm_kroot_message.maclt); | ||||||
|     if (it != OSNMA_TABLE_16.cend()) |     if (it != OSNMA_TABLE_16.cend()) | ||||||
|         { |         { | ||||||
| //            uint8_t msg = it->second.msg; |  | ||||||
| //            uint8_t nt = it->second.nt; |  | ||||||
|             std::vector<std::string> sq1 = it->second.sequence1; |             std::vector<std::string> sq1 = it->second.sequence1; | ||||||
|             std::vector<std::string> sq2 = it->second.sequence2; |             std::vector<std::string> sq2 = it->second.sequence2; | ||||||
|         } |         } | ||||||
|     if (msg == 0) |  | ||||||
|         { |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|     std::vector<std::string> sequence; |     std::vector<std::string> sequence; | ||||||
|     // Assign relevant sequence based on subframe time |     // Assign relevant sequence based on subframe time | ||||||
|     if (d_GST_Sf % 60 == 0) |     if (d_GST_Sf % 60 == 0) | ||||||
| @@ -935,7 +976,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr<OSNMA_msg>& | |||||||
|             std::cout << "Galileo OSNMA: Mismatch in the GST verification => should end in 30 or 60 seconds but it dit not." << std::endl; |             std::cout << "Galileo OSNMA: Mismatch in the GST verification => should end in 30 or 60 seconds but it dit not." << std::endl; | ||||||
|         } |         } | ||||||
|     // compare ADKD of Mack tags with MACLT defined ADKDs |     // compare ADKD of Mack tags with MACLT defined ADKDs | ||||||
|     if(d_osnma_data.d_mack_message.tag_and_info.size() != sq1.size()) |     if(applicable_OSNMA.d_mack_message.tag_and_info.size() != sq1.size()) | ||||||
|         { |         { | ||||||
|           std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; |           std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; | ||||||
|           return; |           return; | ||||||
| @@ -959,7 +1000,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr<OSNMA_msg>& | |||||||
|  |  | ||||||
|     // Fixed as well as  FLX Tags share first part - Eq. 22 ICD |     // Fixed as well as  FLX Tags share first part - Eq. 22 ICD | ||||||
|     std::vector<uint8_t> m(5 + flxTags.size()); |     std::vector<uint8_t> m(5 + flxTags.size()); | ||||||
|     m[0] = static_cast<uint8_t>(osnma_msg->PRN);  // PRN_A |     m[0] = static_cast<uint8_t>(applicable_OSNMA.d_nav_data.PRNa);  // PRN_A | ||||||
|     m[1] = static_cast<uint8_t>((d_GST_Sf & 0xFF000000) >> 24); |     m[1] = static_cast<uint8_t>((d_GST_Sf & 0xFF000000) >> 24); | ||||||
|     m[2] = static_cast<uint8_t>((d_GST_Sf & 0x00FF0000) >> 16); |     m[2] = static_cast<uint8_t>((d_GST_Sf & 0x00FF0000) >> 16); | ||||||
|     m[3] = static_cast<uint8_t>((d_GST_Sf & 0x0000FF00) >> 8); |     m[3] = static_cast<uint8_t>((d_GST_Sf & 0x0000FF00) >> 8); | ||||||
| @@ -968,20 +1009,18 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr<OSNMA_msg>& | |||||||
|     // Case tags flexible - Eq. 21 ICD |     // Case tags flexible - Eq. 21 ICD | ||||||
|     for (uint8_t i = 0; i < flxTags.size() ; i++) |     for (uint8_t i = 0; i < flxTags.size() ; i++) | ||||||
|         { |         { | ||||||
|             m[i+5] = d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; |             m[i+5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; | ||||||
|             m[i+6] = d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; |             m[i+6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | | ||||||
|  |                        applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; | ||||||
|         } |         } | ||||||
|     std::vector<uint8_t> applicable_key; |  | ||||||
|     // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full |  | ||||||
|     // otherwise pick d_old_mack_message.back() |  | ||||||
|     // compute mac |     // compute mac | ||||||
|     applicable_key = d_old_mack_message.back().key; |  | ||||||
|     std::vector<uint8_t> mac; |     std::vector<uint8_t> mac; | ||||||
|     if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 |     if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 | ||||||
|         { |         { | ||||||
|             mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); |             mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); | ||||||
|         } |         } | ||||||
|     else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES |     else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES | ||||||
|         { |         { | ||||||
|             mac = d_crypto->computeCMAC_AES(applicable_key, m); |             mac = d_crypto->computeCMAC_AES(applicable_key, m); | ||||||
|         } |         } | ||||||
| @@ -993,25 +1032,14 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr<OSNMA_msg>& | |||||||
|         } |         } | ||||||
|     uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // TODO - double check, it was 0x0FFF which presuposes little endian... |     uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // TODO - double check, it was 0x0FFF which presuposes little endian... | ||||||
|  |  | ||||||
| //    int num_tags_added = 0; |  | ||||||
|  |  | ||||||
|     // Verify tags if MACSEQ is authenticated |     // Verify tags if MACSEQ is authenticated | ||||||
|     if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) |     if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq) | ||||||
|         { |         { | ||||||
|             std::cout << "OSNMA: MACSEQ authenticated for PRN_A " |             std::cout << "OSNMA: MACSEQ authenticated for PRN_A " | ||||||
|                       << osnma_msg->PRN << " with WN=" |                       << osnma_msg->PRN << " with WN=" | ||||||
|                       << osnma_msg->WN_sf0 << ", TOW=" |                       << osnma_msg->WN_sf0 << ", TOW=" | ||||||
|                       << osnma_msg->TOW_sf0 << ". Verifying tags. " |                       << osnma_msg->TOW_sf0 << ". Verifying tags. " | ||||||
|                       << std::endl; |                       << std::endl; | ||||||
|  |  | ||||||
|             // TODO - configuration file must define which tags shall be verified |  | ||||||
|             // e.g. NavDataVerification: A{0,12,4} == ALL, T == Timing Parameters {4}, ECS == Ephemeris,Clock and Status{0,12}. |  | ||||||
|             std::string navDataToVerify = "EphemerisIonoAndClock"; // ADKD 0 +1 delay ADKD 12 +10 delay |  | ||||||
|             // std::string navDataToVerify = "TimingParameters"; ADKD 4 +1 delay |  | ||||||
|             // std::string navDataToVerify = "ALL"; |  | ||||||
|             std::vector<uint8_t> adkd; |  | ||||||
|             adkd = {0,12,4}; // ADKD will have 0, 12, 4 or any combination of those 3 - maybe more in the future (up to 16 values) |  | ||||||
|             m.clear(); |  | ||||||
|             uint8_t lt_bits = 0; |             uint8_t lt_bits = 0; | ||||||
|             const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); |             const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); | ||||||
|             if (it2 != OSNMA_TABLE_11.cend()) |             if (it2 != OSNMA_TABLE_11.cend()) | ||||||
| @@ -1023,148 +1051,109 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr<OSNMA_msg>& | |||||||
|                     return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. |                     return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |             // Tag verification | ||||||
|  |             // tag[i-1]: | ||||||
|  |                 // adkd = 4/0 : use TK[i], NavData[i-2] to validate Tag[i-1] | ||||||
|  |                 // adkd = 12 : ignore it -> not possible to verify yet | ||||||
|  |             // tag[i-10] | ||||||
|  |                 // adkd = 4/0 : use TK[i-9], NavData[i-11] to validate Tag[i-10] would already be done by tag[i-1] | ||||||
|  |                 // adkd = 12 : use TK[i], NavData[i-11] to validate Tag[i-10] TODO - pending better logic for not repeating this while twice. | ||||||
|  |             int t = d_old_OSNMA_buffer.size() - 2; | ||||||
|  |             applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe | ||||||
|  |             d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ | ||||||
|  |  | ||||||
|  |             int i = 0; | ||||||
|  |             while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message | ||||||
|             // Verify each tag |                 std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs | ||||||
|             // std::string tagsToVerify = "all"; // Ephemeris, UTC, SlowEphemeris, all |                        applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) | ||||||
|             // all -> process ADKD 0, 12 and 4 |                        != d_tags_to_verify.end()) | ||||||
|             // Ephemeris -> process ADKD 0 and 12 only (and if 12, then the applicable key has 10 subframes delay) |  | ||||||
|             // UTC -> process ADKD 4 only |  | ||||||
|             uint8_t i = 0; |  | ||||||
|             while (i < d_osnma_data.d_mack_message.tag_and_info.size() && |  | ||||||
|                 std::find(adkd.begin(),adkd.end(),d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD) != adkd.end()) |  | ||||||
|                 { |                 { | ||||||
|                     // select applicable tesla key |                     // TODO - if a  subsequent tag was already part of the verification (inner loop), this while is going to ignore that and try to validate it anyway. | ||||||
|                     if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0) |  | ||||||
|  |                     // Take tag_k and check its ADKD, COP, PRN_d, this will be the reference for the iteration and search of other Tags | ||||||
|  |                     uint8_t Nt = d_Lt_min / applicable_OSNMA.d_dsm_kroot_message.ts; // Tags needed to be verified | ||||||
|  |                     uint8_t applicable_ADKD = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD; | ||||||
|  |                     uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; | ||||||
|  |                     uint8_t counter_COP = 1; | ||||||
|  |                     uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; | ||||||
|  |                     applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe | ||||||
|  |                     NavData applicable_NavData{}; | ||||||
|  |                     if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) | ||||||
|                         { |                         { | ||||||
|                             applicable_key = d_old_mack_message.back().key; // SF - 1 |                             applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; | ||||||
|                         } |                         } | ||||||
|                     else if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) |                     else if(applicable_ADKD == 12 && d_old_OSNMA_buffer.size() > 11) | ||||||
|  |                         { | ||||||
|  |                             applicable_NavData = d_old_OSNMA_buffer[t - 11].d_nav_data; | ||||||
|  |                         } | ||||||
|  |                     else | ||||||
|  |                         { | ||||||
|  |                             std::cout << "Galileo OSNMA: MACK message buffer elements not enough. Cannot verify tags. " << std::endl; | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                     int k = i + 1; | ||||||
|  |                     uint8_t nt = 0; | ||||||
|  |                     bool flag_cancel_tag_verification = false; // if a tag fails, cancel whole NavData verification set | ||||||
|  |                     // Look for tags relative to reference NavData until Nt achieved, | ||||||
|  |                     // this may require going back in time, as long as COP is valid | ||||||
|  |                     while (nt <= Nt && counter_COP <= applicable_COP && !flag_cancel_tag_verification) | ||||||
|  |                     { | ||||||
|  |                         auto start_it = std::next(applicable_OSNMA.d_mack_message.tag_and_info.begin(), k); | ||||||
|  |  | ||||||
|  |                         // check the vector of tags of aplicable OSNMA for a match against the chosen | ||||||
|  |                         for (auto it = start_it; it != applicable_OSNMA.d_mack_message.tag_and_info.end() && nt <= Nt; ++it) | ||||||
|  |                         { | ||||||
|  |                                 // Check if ADKD, COP, and PRN_d match | ||||||
|  |                                 if(it->tag_info.ADKD == applicable_ADKD | ||||||
|  |                                     // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. | ||||||
|  |                                     && it->tag_info.PRN_d == applicable_PRNd) | ||||||
|  |                                 { | ||||||
|  |                                     if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key )) | ||||||
|  |                                         { | ||||||
|  |                                             nt++; | ||||||
|  |                                         } | ||||||
|  |                                     else | ||||||
|  |                                         { | ||||||
|  |                                            // failure, discard this k-th tag | ||||||
|  |                                            flag_cancel_tag_verification = true; | ||||||
|  |                                            std::cout << "Galileo OSNMA: tag verification failed for PRN_a " | ||||||
|  |                                                      << applicable_OSNMA.d_nav_data.PRNa << " with WN=" | ||||||
|  |                                                      << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" | ||||||
|  |                                                      << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " | ||||||
|  |                                                      << std::endl; | ||||||
|  |                                         } | ||||||
|  |  | ||||||
|  |                                 } | ||||||
|  |                                 if(flag_cancel_tag_verification) | ||||||
|  |                                     break; | ||||||
|  |                         } | ||||||
|  |                         // Check if Nt is achieved, if not, switch to older frame | ||||||
|  |                         if(nt < Nt && t > 0 /*not end of buffer*/ && counter_COP <= applicable_COP && !flag_cancel_tag_verification) | ||||||
|                             { |                             { | ||||||
|                                 // check is the buffer is full or not |                                 t--; | ||||||
|                                 if (d_old_mack_message.size() == d_old_mack_message.capacity()) |                                 applicable_OSNMA = d_old_OSNMA_buffer[t]; | ||||||
|                                     { |                                 applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; | ||||||
|                                         applicable_key = d_old_mack_message.front().key; // SF - 10 |                                 applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; | ||||||
|                                     } |                                 d_GST_Sf -= 30; | ||||||
|                                 else |                                 counter_COP++; | ||||||
|                                     { |                                 k = 0; | ||||||
|                                         std::cout << "Galileo OSNMA: Old MACK message buffer is not full. Cannot verify slow mac. " << std::endl; |  | ||||||
|                                     } |  | ||||||
|                             } |                             } | ||||||
|                     else if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) |                     } | ||||||
|  |  | ||||||
|  |                     if (nt >= Nt) | ||||||
|                         { |                         { | ||||||
|                             applicable_key = d_old_mack_message.back().key; // SF - 1 |                             nt = 0; | ||||||
|                         } |                             std::cout << "Galileo OSNMA: tag verification accumulation succesful for PRN_a " | ||||||
|                     else |                                       << applicable_OSNMA.d_nav_data.PRNa << " with WN=" | ||||||
|                         { |                                       << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" | ||||||
|                         std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; |                                       << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " | ||||||
|  |                                       << std::endl; | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                     // compute m |  | ||||||
|                     m.push_back(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.PRN_d); |  | ||||||
|                     for(int i = 24; i >= 0; i -= 8) |  | ||||||
|                         { |  | ||||||
|                             m.push_back((osnma_msg->PRN >> i) & 0xFF); |  | ||||||
|                         } |  | ||||||
|                     m.push_back(static_cast<uint8_t>((d_GST_Sf & 0xFF000000) >> 24)); |  | ||||||
|                     m.push_back(static_cast<uint8_t>((d_GST_Sf & 0x00FF0000) >> 16)); |  | ||||||
|                     m.push_back(static_cast<uint8_t>((d_GST_Sf & 0x0000FF00) >> 8)); |  | ||||||
|                     m.push_back(static_cast<uint8_t>(d_GST_Sf & 0x000000FF)); |  | ||||||
|                     m.push_back(i+1); // CTR |  | ||||||
|                     m.push_back(d_osnma_data.d_nma_header.nmas); |  | ||||||
|                     if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0 || |  | ||||||
|                         d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) |  | ||||||
|                         { |  | ||||||
|                             m.insert(m.end(),osnma_msg->EphemerisClockAndStatusData.begin(),osnma_msg->EphemerisClockAndStatusData.end()) ; |  | ||||||
|                         } |  | ||||||
|                     else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) |  | ||||||
|                         { |  | ||||||
|                             m.insert(m.end(),osnma_msg->TimingData.begin(),osnma_msg->TimingData.end()) ; |  | ||||||
|                         } |  | ||||||
|                     else |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; |  | ||||||
|                         } |  | ||||||
|                     i = 0; |  | ||||||
|                     // check that m has an integer number of bytes, if not, add padding zeroes |  | ||||||
|                     // padding zeroes until size of vector is an integer number of bytes. |  | ||||||
|                     // I think not needed, if bytes of m correctly formatted (i.e. added in big-endianness) -> the unused bits will be zero |  | ||||||
|                     // and the vector has an integer number of uint8_t elements. |  | ||||||
|  |  | ||||||
|                     // compute mac |  | ||||||
|                     if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 |  | ||||||
|                         { |  | ||||||
|                             mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); |  | ||||||
|                         } |  | ||||||
|                     else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES |  | ||||||
|                         { |  | ||||||
|                             mac = d_crypto->computeCMAC_AES(applicable_key, m); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD |  | ||||||
|                     uint64_t computed_mac = static_cast<uint64_t>(mac[0]) << (lt_bits - 8); |  | ||||||
|                     computed_mac += (static_cast<uint64_t>(mac[1]) << (lt_bits - 16)); |  | ||||||
|                     if (lt_bits == 20) |  | ||||||
|                         { |  | ||||||
|                             computed_mac += (static_cast<uint64_t>(mac[1] & 0xF0) >> 4); |  | ||||||
|                         } |  | ||||||
|                     else if (lt_bits == 24) |  | ||||||
|                         { |  | ||||||
|                             computed_mac += static_cast<uint64_t>(mac[2]); |  | ||||||
|                         } |  | ||||||
|                     else if (lt_bits == 28) |  | ||||||
|                         { |  | ||||||
|                             computed_mac += (static_cast<uint64_t>(mac[2]) << 4); |  | ||||||
|                             computed_mac += (static_cast<uint64_t>(mac[3] & 0xF0) >> 4); |  | ||||||
|                         } |  | ||||||
|                     else if (lt_bits == 32) |  | ||||||
|                         { |  | ||||||
|                             computed_mac += (static_cast<uint64_t>(mac[2]) << 8); |  | ||||||
|                             computed_mac += static_cast<uint64_t>(mac[3]); |  | ||||||
|                         } |  | ||||||
|                     else if (lt_bits == 40) |  | ||||||
|                         { |  | ||||||
|                             computed_mac += (static_cast<uint64_t>(mac[2]) << 16); |  | ||||||
|                             computed_mac += (static_cast<uint64_t>(mac[3]) << 8); |  | ||||||
|                             computed_mac += static_cast<uint64_t>(mac[4]); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     // Compare computed tag with received one truncated |  | ||||||
|                     if (d_osnma_data.d_mack_message.tag_and_info[i].tag == computed_mac) |  | ||||||
|                         { |  | ||||||
|                             if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0 || d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) |  | ||||||
|                                 { |  | ||||||
|                                     std::cout << "Galileo OSNMA: Tag verification successful - Ephemeris, Clock and Ionospheric data " << std::endl; |  | ||||||
|                                     d_Lt_verified_eph += lt_bits; |  | ||||||
|                                 } |  | ||||||
|                             else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) |  | ||||||
|                                 { |  | ||||||
|                                     std::cout << "Galileo OSNMA: Tag verification successful - Timing data " << std::endl; |  | ||||||
|                                     d_Lt_verified_utc += lt_bits; |  | ||||||
|                                 } |  | ||||||
|                         } |  | ||||||
|                     else |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Galileo OSNMA: Tag verification failed " << std::endl; |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     if (d_Lt_verified_eph >= d_Lt_min) |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Galileo OSNMA: Ephemeris, Clock and Ionospheric data verified successfully " << std::endl; |  | ||||||
|                             d_Lt_verified_eph = 0; |  | ||||||
|                             // send info to PVT: navdata SF i-1 authenticated |  | ||||||
|                             break; |  | ||||||
|                         } |  | ||||||
|                     if (d_Lt_verified_utc >= d_Lt_min) |  | ||||||
|                         { |  | ||||||
|                             std::cout << "Galileo OSNMA: Timing data verified successfully " << std::endl; |  | ||||||
|                             d_Lt_verified_utc = 0; |  | ||||||
|                             // send info to PVT: navdata SF i-1 authenticated |  | ||||||
|                             break; |  | ||||||
|                         } |  | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1212,3 +1201,154 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| } | } | ||||||
|  | bool osnma_msg_receiver::verify_tag(MACK_tag_and_info tag_and_info, | ||||||
|  |     OSNMA_data applicable_OSNMA, uint8_t tag_position, | ||||||
|  |     const std::vector<uint8_t>& applicable_key, | ||||||
|  |     NavData applicable_NavData) | ||||||
|  | { | ||||||
|  |     bool verified = false; | ||||||
|  |     auto CTR = tag_position + 2; // CTR, first tag is CTR(tag0)=1 + 1 == 2 | ||||||
|  |     // NAvData, tag_and_info[i] | ||||||
|  |  | ||||||
|  |     // check if enough osnma messages stored in the buffer. | ||||||
|  |     if (tag_and_info.tag_info.ADKD == 0 | ||||||
|  |         || tag_and_info.tag_info.ADKD == 4) | ||||||
|  |         { | ||||||
|  |             if (d_old_OSNMA_buffer.size() < 3) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Galileo OSNMA: MACK message buffer empty. Cannot verify tags. " << std::endl; | ||||||
|  |                     return verified; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |     else if (tag_and_info.tag_info.ADKD == 12) | ||||||
|  |         { | ||||||
|  |  | ||||||
|  |             if (d_old_OSNMA_buffer.size() < 10+15) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Galileo OSNMA: Tesla key not yet available. Cannot verify slow mac. at " << | ||||||
|  |                         d_receiver_time << "s. "<< std::endl; | ||||||
|  |                     return verified; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; | ||||||
|  |             return verified; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // compute m | ||||||
|  |     std::vector<uint8_t> m; | ||||||
|  |     m.push_back(tag_and_info.tag_info.PRN_d); | ||||||
|  |     for(int i = 24; i >= 0; i -= 8) | ||||||
|  |         { | ||||||
|  |             m.push_back((applicable_NavData.PRNa >> i) & 0xFF); | ||||||
|  |         } | ||||||
|  |     m.push_back(static_cast<uint8_t>((d_GST_Sf & 0xFF000000) >> 24)); | ||||||
|  |     m.push_back(static_cast<uint8_t>((d_GST_Sf & 0x00FF0000) >> 16)); | ||||||
|  |     m.push_back(static_cast<uint8_t>((d_GST_Sf & 0x0000FF00) >> 8)); | ||||||
|  |     m.push_back(static_cast<uint8_t>(d_GST_Sf & 0x000000FF)); | ||||||
|  |     m.push_back(CTR); | ||||||
|  |     m.push_back(applicable_OSNMA.d_nma_header.nmas); | ||||||
|  |     if(tag_and_info.tag_info.ADKD == 0) | ||||||
|  |         { | ||||||
|  |             m.insert(m.end(), | ||||||
|  |                 applicable_NavData.ephemeris_iono_vector.begin(), | ||||||
|  |                 applicable_NavData.ephemeris_iono_vector.end()) ; | ||||||
|  |         } | ||||||
|  |     else if(tag_and_info.tag_info.ADKD == 4) | ||||||
|  |         { | ||||||
|  |             m.insert(m.end(),applicable_NavData.utc_vector.begin(),applicable_NavData.utc_vector.end()) ; | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // check that m has an integer number of bytes, if not, add padding zeroes | ||||||
|  |     // padding zeroes until size of vector is an integer number of bytes. | ||||||
|  |     // I think not needed, if bytes of m correctly formatted (i.e. added in big-endianness) -> the unused bits will be zero | ||||||
|  |     // and the vector has an integer number of uint8_t elements. | ||||||
|  |  | ||||||
|  |     // compute mac | ||||||
|  |     std::vector<uint8_t> mac; | ||||||
|  |     if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 | ||||||
|  |         { | ||||||
|  |             mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); | ||||||
|  |         } | ||||||
|  |     else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES | ||||||
|  |         { | ||||||
|  |             mac = d_crypto->computeCMAC_AES(applicable_key, m); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD | ||||||
|  |     uint8_t lt_bits = 0; // TODO - remove this duplication of code. | ||||||
|  |     const auto it2 = OSNMA_TABLE_11.find(applicable_OSNMA.d_dsm_kroot_message.ts); | ||||||
|  |     if (it2 != OSNMA_TABLE_11.cend()) | ||||||
|  |         { | ||||||
|  |             lt_bits = it2->second; | ||||||
|  |         } | ||||||
|  |     if (lt_bits == 0) | ||||||
|  |         { | ||||||
|  |             return verified; | ||||||
|  |         } | ||||||
|  |     uint64_t computed_mac = static_cast<uint64_t>(mac[0]) << (lt_bits - 8); | ||||||
|  |     computed_mac += (static_cast<uint64_t>(mac[1]) << (lt_bits - 16)); | ||||||
|  |     if (lt_bits == 20) | ||||||
|  |         { | ||||||
|  |             computed_mac += (static_cast<uint64_t>(mac[1] & 0xF0) >> 4); | ||||||
|  |         } | ||||||
|  |     else if (lt_bits == 24) | ||||||
|  |         { | ||||||
|  |             computed_mac += static_cast<uint64_t>(mac[2]); | ||||||
|  |         } | ||||||
|  |     else if (lt_bits == 28) | ||||||
|  |         { | ||||||
|  |             computed_mac += (static_cast<uint64_t>(mac[2]) << 4); | ||||||
|  |             computed_mac += (static_cast<uint64_t>(mac[3] & 0xF0) >> 4); | ||||||
|  |         } | ||||||
|  |     else if (lt_bits == 32) | ||||||
|  |         { | ||||||
|  |             computed_mac += (static_cast<uint64_t>(mac[2]) << 8); | ||||||
|  |             computed_mac += static_cast<uint64_t>(mac[3]); | ||||||
|  |         } | ||||||
|  |     else if (lt_bits == 40) | ||||||
|  |         { | ||||||
|  |             computed_mac += (static_cast<uint64_t>(mac[2]) << 16); | ||||||
|  |             computed_mac += (static_cast<uint64_t>(mac[3]) << 8); | ||||||
|  |             computed_mac += static_cast<uint64_t>(mac[4]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     // Compare computed tag with received one truncated | ||||||
|  |     if (tag_and_info.tag == computed_mac) | ||||||
|  |         { | ||||||
|  |             verified = true; | ||||||
|  |             if(tag_and_info.tag_info.ADKD == 0 || tag_and_info.tag_info.ADKD == 12) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Galileo OSNMA: tag verification successful for PRN_a " | ||||||
|  |                               << applicable_NavData.PRNa << " with WN=" | ||||||
|  |                               << applicable_NavData.WN_sf0 << ", TOW=" | ||||||
|  |                               << applicable_NavData.TOW_sf0 << "NavData= " | ||||||
|  |                               << "Ephemeris, Clock and Ionospheric data" << ". " | ||||||
|  |                               << std::endl; | ||||||
|  |                 } | ||||||
|  |             else if(tag_and_info.tag_info.ADKD == 4) | ||||||
|  |                 { | ||||||
|  |                     std::cout << "Galileo OSNMA: tag verification successful for PRN_a " | ||||||
|  |                               << applicable_NavData.PRNa << " with WN=" | ||||||
|  |                               << applicable_NavData.WN_sf0 << ", TOW=" | ||||||
|  |                               << applicable_NavData.TOW_sf0 << "NavData= " | ||||||
|  |                               << "Timing data" << ". " | ||||||
|  |                               << std::endl; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |     else | ||||||
|  |         { | ||||||
|  |             std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " | ||||||
|  |                       << applicable_NavData.PRNa << " with WN=" | ||||||
|  |                       << applicable_NavData.WN_sf0 << ", TOW=" | ||||||
|  |                       << applicable_NavData.TOW_sf0 << ". " | ||||||
|  |                       << std::endl; | ||||||
|  |         } | ||||||
|  |     return verified; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -68,13 +68,14 @@ private: | |||||||
|     void process_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg); |     void process_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg); | ||||||
|     void process_dsm_message(const std::vector<uint8_t>& dsm_msg, const std::shared_ptr<OSNMA_msg>& osnma_msg); |     void process_dsm_message(const std::vector<uint8_t>& dsm_msg, const std::shared_ptr<OSNMA_msg>& osnma_msg); | ||||||
|     bool verify_dsm_pkr(DSM_PKR_message message); |     bool verify_dsm_pkr(DSM_PKR_message message); | ||||||
|     void read_mack_block(const std::shared_ptr<OSNMA_msg>& osnma_msg); |     void read_and_process_mack_block(const std::shared_ptr<OSNMA_msg>& osnma_msg); | ||||||
|     void read_mack_header(); |     void read_mack_header(); | ||||||
|     void read_mack_body(); |     void read_mack_body(); | ||||||
|     void process_mack_message(const std::shared_ptr<OSNMA_msg>& osnma_msg); |     void process_mack_message(const std::shared_ptr<OSNMA_msg>& osnma_msg); | ||||||
|  |     bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector<uint8_t>& applicable_key, NavData applicable_NavData); | ||||||
|  |  | ||||||
|     boost::circular_buffer<MACK_message> d_old_mack_message; |     //boost::circular_buffer<MACK_message> d_old_mack_message; | ||||||
|     boost::circular_buffer<NavData> d_old_navdata_buffer; // buffer that holds last 10 received navdata messages |     boost::circular_buffer<OSNMA_data> d_old_OSNMA_buffer; // buffer that holds last 12 received OSNMA messages, including current one at back() | ||||||
|     std::unique_ptr<OSNMA_DSM_Reader> d_dsm_reader; |     std::unique_ptr<OSNMA_DSM_Reader> d_dsm_reader; | ||||||
|     std::unique_ptr<Gnss_Crypto> d_crypto; |     std::unique_ptr<Gnss_Crypto> d_crypto; | ||||||
|  |  | ||||||
| @@ -92,10 +93,14 @@ private: | |||||||
|     uint8_t d_Lt_min {}; // minimum equivalent tag length |     uint8_t d_Lt_min {}; // minimum equivalent tag length | ||||||
|     uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris |     uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris | ||||||
|     uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing |     uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing | ||||||
|  |     uint8_t const d_T_L{30}; // s RG Section 2.1 | ||||||
|  |     uint8_t const d_delta_COP{30}; // s SIS ICD Table 14 | ||||||
|     uint32_t d_GST_0 {}; |     uint32_t d_GST_0 {}; | ||||||
|     uint32_t d_GST_SIS {}; |     uint32_t d_GST_SIS {}; | ||||||
|     std::time_t d_receiver_time {0}; |     std::time_t d_receiver_time {0}; | ||||||
|     const uint8_t d_T_L{30}; // s RG Section 2.1 |     enum tags_to_verify{all,utc,slow_eph, eph, none}; // TODO is this safe? I hope so | ||||||
|  |     tags_to_verify d_tags_allowed{tags_to_verify::all}; | ||||||
|  |     std::vector<uint8_t> d_tags_to_verify{0,4,12}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -16,37 +16,27 @@ | |||||||
|  |  | ||||||
| #include "osnma_data.h" | #include "osnma_data.h" | ||||||
| #include <cstring> | #include <cstring> | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief Constructs a NavData object with the given osnma_msg. | ||||||
|  |  * \details Packs the ephemeris, iono and utc data from the current subframe into the NavData structure. It also gets the PRNa and the GST. | ||||||
|  |  * @param osnma_msg The shared pointer to the OSNMA_msg object. | ||||||
|  |  */ | ||||||
|  | void NavData::init(const std::shared_ptr<OSNMA_msg> &osnma_msg) | ||||||
|  | { | ||||||
|  |     EphemerisData = osnma_msg->EphemerisData; | ||||||
|  |     IonoData = osnma_msg->IonoData; | ||||||
|  |     UtcData = osnma_msg->UtcModelData; | ||||||
|  |     generate_eph_iono_vector(); | ||||||
|  |     generate_utc_vector(); | ||||||
|  |     PRNa = osnma_msg->PRN; | ||||||
|  |     WN_sf0 = osnma_msg->WN_sf0; | ||||||
|  |     TOW_sf0 = osnma_msg->TOW_sf0; | ||||||
|  | }; | ||||||
| void NavData::generate_eph_iono_vector() | void NavData::generate_eph_iono_vector() | ||||||
| { | { | ||||||
|     ephemeris_iono_vector.clear(); |     ephemeris_iono_vector.clear(); | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>((EphemerisData.IOD_nav & 0b0000'0000'0000'0000'0000'0011'1111'1100) >> 2)); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>((EphemerisData.IOD_nav & 0b0000'0000'0000'0000'0000'0000'0000'0011) << 6 |  | ||||||
|                                     | (EphemerisData.toe & 0b0000'0000'0000'0000'0011'1111'1111'1111) >> 8)); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(EphemerisData.toe)); |  | ||||||
|     uint64_t binary_representation; |  | ||||||
|     memcpy(&binary_representation, &EphemerisData.M_0, sizeof(EphemerisData.M_0)); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 8))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 16))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 24))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 32))); |  | ||||||
|     memcpy(&binary_representation, &EphemerisData.ecc, sizeof(EphemerisData.ecc)); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 8))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 16))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 24))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 32))); |  | ||||||
|     memcpy(&binary_representation, &EphemerisData.sqrtA, sizeof(EphemerisData.sqrtA)); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 8))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 16))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 24))); |  | ||||||
|     ephemeris_iono_vector.push_back(static_cast<uint8_t>(binary_representation >> (64 - 32))); |  | ||||||
|  |  | ||||||
|     // TODO: Implement the function to generate the rest of pages |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NavData::generate_eph_iono_vector2() |  | ||||||
| { |  | ||||||
|     std::vector<uint8_t> eph_iono_vector; |  | ||||||
|     uint64_t bit_buffer = 0; // variable to store the bits to be extracted, it can contain bits from different variables |     uint64_t bit_buffer = 0; // variable to store the bits to be extracted, it can contain bits from different variables | ||||||
|     int bit_count = 0; // Number of bits in the buffer, i.e. to be extracted |     int bit_count = 0; // Number of bits in the buffer, i.e. to be extracted | ||||||
|  |  | ||||||
| @@ -113,7 +103,7 @@ void NavData::generate_eph_iono_vector2() | |||||||
|         { |         { | ||||||
|             // Extract the 8 bits starting from last bit position and add them to the vector |             // Extract the 8 bits starting from last bit position and add them to the vector | ||||||
|             uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; |             uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; | ||||||
|             eph_iono_vector.push_back(extracted_bits); |             ephemeris_iono_vector.push_back(extracted_bits); | ||||||
|  |  | ||||||
|             // Remove the extracted bits from the buffer |             // Remove the extracted bits from the buffer | ||||||
|             bit_count -= 8; |             bit_count -= 8; | ||||||
| @@ -125,7 +115,7 @@ void NavData::generate_eph_iono_vector2() | |||||||
|     // If there are any bits left in the buffer, add them to the vector |     // If there are any bits left in the buffer, add them to the vector | ||||||
|     if (bit_count > 0) |     if (bit_count > 0) | ||||||
|     { |     { | ||||||
|         eph_iono_vector.push_back(static_cast<uint8_t>(bit_buffer)); |         ephemeris_iono_vector.push_back(static_cast<uint8_t>(bit_buffer)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -173,13 +163,3 @@ void NavData::generate_utc_vector() | |||||||
|             utc_vector.push_back(static_cast<uint8_t>(bit_buffer)); |             utc_vector.push_back(static_cast<uint8_t>(bit_buffer)); | ||||||
|         } |         } | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<uint8_t> NavData::get_eph_iono_vector() |  | ||||||
| { |  | ||||||
|     return ephemeris_iono_vector; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::vector<uint8_t> NavData::get_utc_vector() |  | ||||||
| { |  | ||||||
|     return utc_vector; |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ | |||||||
| #define GNSS_SDR_OSNMA_DATA_H | #define GNSS_SDR_OSNMA_DATA_H | ||||||
|  |  | ||||||
| #include "galileo_ephemeris.h" | #include "galileo_ephemeris.h" | ||||||
|  | #include "galileo_inav_message.h" | ||||||
| #include "galileo_iono.h" | #include "galileo_iono.h" | ||||||
| #include "galileo_utc_model.h" | #include "galileo_utc_model.h" | ||||||
| #include <array> | #include <array> | ||||||
| @@ -125,18 +126,20 @@ public: | |||||||
| class NavData | class NavData | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     NavData() = default; |     NavData()=default; | ||||||
|  |     void init(const std::shared_ptr<OSNMA_msg> &osnma_msg); | ||||||
|  |     std::vector<uint8_t> ephemeris_iono_vector{}; | ||||||
|  |     std::vector<uint8_t> utc_vector{}; | ||||||
|  |     uint32_t PRNa{}; | ||||||
|  |     uint32_t WN_sf0{}; | ||||||
|  |     uint32_t TOW_sf0{}; | ||||||
|  | private: | ||||||
|     Galileo_Ephemeris EphemerisData; |     Galileo_Ephemeris EphemerisData; | ||||||
|     Galileo_Iono IonoData; |     Galileo_Iono IonoData; | ||||||
|     Galileo_Utc_Model UtcData; |     Galileo_Utc_Model UtcData; | ||||||
|     void generate_eph_iono_vector(); // TODO check with Carles procedure and compare with v2 |     void generate_eph_iono_vector(); // TODO pass data directly fro Telemetry Decoder (if bits are in the needed order) | ||||||
|     void generate_eph_iono_vector2(); |  | ||||||
|     void generate_utc_vector(); // TODO |     void generate_utc_vector(); // TODO | ||||||
|     std::vector<uint8_t> get_eph_iono_vector(); // TODO |  | ||||||
|     std::vector<uint8_t> get_utc_vector(); // TODO |  | ||||||
| private: |  | ||||||
|     std::vector<uint8_t> ephemeris_iono_vector; |  | ||||||
|     std::vector<uint8_t> utc_vector; |  | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 cesaaargm
					cesaaargm