1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-12 19:20:32 +00:00

[TAS-255] [BUG] Assure time synch. is properly done

if d_flag_debug=false, now system clock is used to for the receiver synchronisation. It uses the UTC time and the GST epoch start time (adjusted for local time zone difference) to create a local estimation of GST, then compares with GST_SIS (coming from NavData Words 5 and 6)
This commit is contained in:
cesaaargm 2024-08-01 11:52:28 +02:00
parent 2db37f384e
commit a47cf1187c
5 changed files with 141 additions and 128 deletions

View File

@ -112,6 +112,21 @@ osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std
boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, _1)); boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, _1));
#endif #endif
#endif #endif
std::chrono::time_point<std::chrono::system_clock> now;
if (d_flag_debug){
// d_GST_Rx = d_helper->compute_gst(d_initial_debug_time);
LOG(WARNING) << "Galileo OSNMA: Debug mode, time artificially set up.";
std::cout << "Galileo OSNMA: Debug mode, time artificially set up." << std::endl;
// TODO - need to synchronize time lapse with Gnss_Synchro?
}
else{
d_GST_Rx = d_helper->compute_gst_now();
}
d_WN = d_helper->get_WN(d_GST_Rx);
d_TOW = d_helper->get_TOW(d_GST_Rx);
LOG(WARNING) << "Galileo OSNMA: initial receiver time GST=["<< d_WN << " " << d_TOW <<"]";
std::cout << "Galileo OSNMA: initial receiver time GST=["<< d_WN << " " << d_TOW <<"]" << std::endl;
} }
@ -138,6 +153,50 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg)
LOG(INFO) << output_message.str(); LOG(INFO) << output_message.str();
std::cout << output_message.str() << std::endl; std::cout << output_message.str() << std::endl;
// Receiver time update
d_GST_SIS = d_helper->compute_gst(nma_msg->WN_sf0, nma_msg->TOW_sf0);
if (d_last_verified_key_GST == 0){
d_last_received_GST = d_GST_SIS;
}
else if (d_GST_SIS > d_last_received_GST){
d_last_received_GST = d_GST_SIS;
}
if (d_flag_debug){
d_GST_Rx = d_last_received_GST;
}
else{
d_GST_Rx = d_helper->compute_gst_now();
}
LOG(INFO) << "Galileo OSNMA: Receiver Time GST=[" << d_helper->get_WN(d_GST_Rx) << " " << d_helper->get_TOW(d_GST_Rx) << "]";
std::cout << "Galileo OSNMA: Receiver Time GST=[" << d_helper->get_WN(d_GST_Rx) << " " << d_helper->get_TOW(d_GST_Rx) << "]" << std::endl;
// time constraint verification
std::time_t delta_T = std::abs(static_cast<int64_t>(d_GST_Rx - d_GST_SIS));
if (delta_T <= d_T_L)
{
d_tags_to_verify = {0, 4, 12};
LOG(INFO) << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)";
std::cout << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)" << std::endl;
}
else if (delta_T > d_T_L && delta_T <= 10 * d_T_L)
{
d_tags_to_verify = {12};
LOG(WARNING) << "Galileo OSNMA: time constraint allows only slow MACs to be verified";
std::cout << "Galileo OSNMA: |local_t - GST_SIS| < T_L [ |" << static_cast<int>(d_GST_Rx - d_GST_SIS) << " | < " << static_cast<int>(d_T_L) << " ]" << std::endl;
LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_GST_Rx << " d_GST_SIS: " << d_GST_SIS;
LOG(WARNING) << "Galileo OSNMA: |local_t - GST_SIS| < T_L [ |" << static_cast<int>(d_GST_Rx - d_GST_SIS) << " | < " << static_cast<int>(d_T_L) << " ]";
}
else
{
d_tags_to_verify = {};
LOG(WARNING) << "Galileo OSNMA: time constraint violation";
std::cerr << "Galileo OSNMA: time constraint violation" << std::endl;
std::cerr << "Galileo OSNMA: | local_t - GST_SIS | < T_L [ | " << static_cast<int>(d_GST_Rx - d_GST_SIS) << " | < " << static_cast<int>(d_T_L) << " ]" << std::endl;
LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_GST_Rx << " d_GST_SIS: " << d_GST_SIS;
LOG(WARNING) << "Galileo OSNMA: | local_t - GST_SIS | < T_L [ | " << static_cast<int>(d_GST_Rx - d_GST_SIS) << " | < " << static_cast<int>(d_T_L) << " ]";
return;
}
process_osnma_message(nma_msg); process_osnma_message(nma_msg);
} // OSNMA frame received } // OSNMA frame received
else if (msg_type_hash_code == typeid(std::shared_ptr<std::tuple<uint32_t, std::string, uint32_t>>).hash_code()) // Navigation data bits for OSNMA received else if (msg_type_hash_code == typeid(std::shared_ptr<std::tuple<uint32_t, std::string, uint32_t>>).hash_code()) // Navigation data bits for OSNMA received
@ -159,7 +218,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg)
} }
// Send the resulting decoded NMA data (if available) to PVT // Send the resulting decoded NMA data (if available) to PVT
if (d_new_data) // TODO where is it set to true? if (d_new_data)
{ {
auto osnma_data_ptr = std::make_shared<OSNMA_data>(d_osnma_data); auto osnma_data_ptr = std::make_shared<OSNMA_data>(d_osnma_data);
this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr));
@ -177,13 +236,14 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>&
} }
read_nma_header(osnma_msg->hkroot[0]); read_nma_header(osnma_msg->hkroot[0]);
// Check for corner cases: renewal, revocation // Check for corner cases: renewal, revocation, alert message
if (d_osnma_data.d_nma_header.nmas == 0 /* RES */){ if (d_osnma_data.d_nma_header.nmas == 0 /* RES */){
LOG(WARNING) << "Galileo OSNMA: NMAS invalid (RES), skipping osnma message"; LOG(WARNING) << "Galileo OSNMA: NMAS invalid (RES), skipping osnma message";
return; return;
} }
// TODO - trusting the NMAS and CPKS shall be done upon PKR verification or Tag verification. // TODO - trusting the NMAS and CPKS shall be done upon PKR verification or Tag verification.
// It's ok to activate the flags, but the final decision should happen after verifying it. // It's ok to activate the flags, but the final decision should happen after verifying it.
// For OAM is solved, but NPK and PKREV I think not yet
if (d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 4 /* NPK */ && d_GST_PKR_PKREV_start == 0){ if (d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 4 /* NPK */ && d_GST_PKR_PKREV_start == 0){
d_flag_PK_renewal = true; d_flag_PK_renewal = true;
d_GST_PKR_PKREV_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); d_GST_PKR_PKREV_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0);
@ -229,9 +289,9 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>&
read_dsm_header(osnma_msg->hkroot[1]); read_dsm_header(osnma_msg->hkroot[1]);
read_dsm_block(osnma_msg); read_dsm_block(osnma_msg);
process_dsm_block(osnma_msg); // will process dsm block if received a complete one, then will call mack processing upon re-setting the dsm block to 0 process_dsm_block(osnma_msg); // will process dsm block if received a complete one, then will call mack processing upon re-setting the dsm block to 0
if (d_osnma_data.d_dsm_kroot_message.towh_k != 0) if (d_osnma_data.d_dsm_kroot_message.towh_k != 0){
{ d_GST_0 = d_helper->compute_gst(d_osnma_data.d_dsm_kroot_message.wn_k, d_osnma_data.d_dsm_kroot_message.towh_k * 3600);
local_time_verification(osnma_msg); d_GST_Sf = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G.
} }
read_and_process_mack_block(osnma_msg); // only process them if at least 3 available. read_and_process_mack_block(osnma_msg); // only process them if at least 3 available.
} }
@ -350,63 +410,6 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_
std::cout << available_blocks.str() << std::endl; std::cout << available_blocks.str() << std::endl;
} }
/**
* @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)
{
// compute local time based on GST_SIS and GST_0
d_GST_SIS = (osnma_msg->WN_sf0 & 0x00000FFF) << 20 | (osnma_msg->TOW_sf0 & 0x000FFFFF);
// std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl;
// d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30;
d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k * 3600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30)
// d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30;
// TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID.
if (d_receiver_time != 0)
{
d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G.
// d_receiver_time += 30;
// std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl;
}
else
{ // local time not initialised -> compute it.
d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G.
// std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl;
}
// verify time constraint
std::time_t delta_T = std::abs(static_cast<int64_t>(d_receiver_time - d_GST_SIS));
if (delta_T <= d_T_L)
{
d_tags_allowed = tags_to_verify::all;
d_tags_to_verify = {0, 4, 12};
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
}
else if (delta_T > d_T_L && delta_T <= 10 * d_T_L)
{
d_tags_allowed = tags_to_verify::slow_eph;
d_tags_to_verify = {12};
LOG(WARNING) << "Galileo OSNMA: time constraint allows only slow MACs to be verified";
LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS;
LOG(WARNING) << "Galileo OSNMA: ( |local_t - GST_SIS| < T_L ) [ |" << static_cast<int>(d_receiver_time - d_GST_SIS) << " | < " << static_cast<int>(d_T_L) << " ]";
}
else
{
d_tags_allowed = tags_to_verify::none;
d_tags_to_verify = {};
LOG(WARNING) << "Galileo OSNMA: time constraint violation";
LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS;
LOG(WARNING) << "Galileo OSNMA: ( |local_t - GST_SIS| < T_L ) [ |" << static_cast<int>(d_receiver_time - d_GST_SIS) << " | < " << static_cast<int>(d_T_L) << " ]";
}
}
/** /**
* @brief Process DSM block of an OSNMA message. * @brief Process DSM block of an OSNMA message.
* *
@ -671,7 +674,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
else if (d_flag_alert_message){ else if (d_flag_alert_message){
LOG(WARNING) << "Galileo OSNMA: DSM-PKR verification :: Alert message verification :: SUCCESS. OSNMA disabled. Contact Galileo Service Centre"; LOG(WARNING) << "Galileo OSNMA: DSM-PKR verification :: Alert message verification :: SUCCESS. OSNMA disabled. Contact Galileo Service Centre";
std::cout << "Galileo OSNMA: DSM-PKR verification :: Alert message verification :: SUCCESS. OSNMA disabled. Contact Galileo Service Centre" << std::endl; std::cout << "Galileo OSNMA: DSM-PKR verification :: Alert message verification :: SUCCESS. OSNMA disabled. Contact Galileo Service Centre" << std::endl;
} }
else{ else{
d_crypto->d_PublicKeyType = PKT; d_crypto->d_PublicKeyType = PKT;
@ -686,7 +688,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
d_count_failed_pubKey ++; d_count_failed_pubKey ++;
if (d_flag_alert_message){ if (d_flag_alert_message){
d_flag_alert_message = false; // disregard message as its authenticity could not be verified. d_flag_alert_message = false; // disregard message as its authenticity could not be verified.
} }
} }
} }
@ -725,8 +726,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr<OSNMA
(d_osnma_data.d_nma_header.nmas == 3 && !d_kroot_verified); // NMAS is DU, but must be disregarded (d_osnma_data.d_nma_header.nmas == 3 && !d_kroot_verified); // NMAS is DU, but must be disregarded
bool can_verify_tesla_key = d_kroot_verified || d_tesla_key_verified; // Either of those suffices for verifying the incoming TESLA key bool can_verify_tesla_key = d_kroot_verified || d_tesla_key_verified; // Either of those suffices for verifying the incoming TESLA key
bool can_parse_tag_fields = d_osnma_data.d_dsm_kroot_message.ts != 0; // calculating the number of tags is based on the TS of the DSM-KROOT. bool can_parse_tag_fields = d_osnma_data.d_dsm_kroot_message.ts != 0; // calculating the number of tags is based on the TS of the DSM-KROOT.
if (can_verify_tesla_key && can_parse_tag_fields && can_process_mack_block) if (can_verify_tesla_key && can_parse_tag_fields && can_process_mack_block){
{ // TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future
read_mack_header(); read_mack_header();
d_osnma_data.d_mack_message.PRNa = osnma_msg->PRN; // FIXME this is ugly. d_osnma_data.d_mack_message.PRNa = osnma_msg->PRN; // FIXME this is ugly.
d_osnma_data.d_mack_message.TOW = osnma_msg->TOW_sf0; d_osnma_data.d_mack_message.TOW = osnma_msg->TOW_sf0;
@ -1012,14 +1012,8 @@ void osnma_msg_receiver::process_mack_message()
{ {
LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed, " LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed, "
<< "no Kroot nor TESLA key available."; << "no Kroot nor TESLA key available.";
if (!d_flag_debug)
{
return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet.
}
else
{
LOG(WARNING) << "Galileo OSNMA: But it will be processed for debugging purposes.";
}
} }
// verify tesla key and add it to the container of verified keys if successful // verify tesla key and add it to the container of verified keys if successful
if (d_tesla_keys.find(d_osnma_data.d_nav_data.get_tow_sf0()) == d_tesla_keys.end()) // check if already available => no need to verify if (d_tesla_keys.find(d_osnma_data.d_nav_data.get_tow_sf0()) == d_tesla_keys.end()) // check if already available => no need to verify
@ -1425,14 +1419,14 @@ void osnma_msg_receiver::display_data()
bool osnma_msg_receiver::verify_tesla_key(std::vector<uint8_t>& key, uint32_t TOW) bool osnma_msg_receiver::verify_tesla_key(std::vector<uint8_t>& key, uint32_t TOW)
{ {
uint32_t num_of_hashes_needed; uint32_t num_of_hashes_needed;
uint32_t GST_SFi = d_receiver_time - 30; // GST of target key is to be used. uint32_t GST_SFi = d_GST_Sf - 30; // GST of target key is to be used.
std::vector<uint8_t> hash; std::vector<uint8_t> hash;
const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8;
std::vector<uint8_t> validated_key; std::vector<uint8_t> validated_key;
if (d_tesla_key_verified) if (d_tesla_key_verified)
{ // have to go up to last verified key { // have to go up to last verified key
validated_key = d_tesla_keys.rbegin()->second; validated_key = d_tesla_keys.rbegin()->second;
num_of_hashes_needed = (d_receiver_time - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified num_of_hashes_needed = (d_GST_Sf - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified
LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key"; LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key";
hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes);
@ -1440,7 +1434,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector<uint8_t>& key, uint32_t TO
else else
{ // have to go until Kroot { // have to go until Kroot
validated_key = d_osnma_data.d_dsm_kroot_message.kroot; validated_key = d_osnma_data.d_dsm_kroot_message.kroot;
num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 IC num_of_hashes_needed = (d_GST_Sf - d_GST_0) / 30 + 1; // Eq. 19 IC
LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to Kroot"; LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to Kroot";
hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes);
@ -1458,24 +1452,16 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector<uint8_t>& key, uint32_t TO
std::cout << "Galileo OSNMA: TESLA key verification :: SUCCESS!" << std::endl; std::cout << "Galileo OSNMA: TESLA key verification :: SUCCESS!" << std::endl;
d_tesla_keys.insert(std::pair<uint32_t, std::vector<uint8_t>>(TOW, key)); d_tesla_keys.insert(std::pair<uint32_t, std::vector<uint8_t>>(TOW, key));
d_tesla_key_verified = true; d_tesla_key_verified = true;
d_last_verified_key_GST = d_receiver_time; d_last_verified_key_GST = d_GST_Sf;
} }
else if (num_of_hashes_needed > 0) else if (num_of_hashes_needed > 0)
{ {
LOG(WARNING) << "Galileo OSNMA: TESLA key verification :: FAILED"; LOG(WARNING) << "Galileo OSNMA: TESLA key verification :: FAILED";
std::cerr << "Galileo OSNMA: TESLA key verification :: FAILED" << std::endl; std::cerr << "Galileo OSNMA: TESLA key verification :: FAILED" << std::endl;
if (d_flag_debug)
{
d_tesla_keys.insert(std::pair<uint32_t, std::vector<uint8_t>>(TOW, key));
d_last_verified_key_GST = d_receiver_time;
d_tesla_key_verified = true;
// TODO - if intermediate verification fails, can one still use the former verified tesla key or should go to Kroot or even retrieve new Kroot?
}
} }
return d_tesla_key_verified; return d_tesla_key_verified;
} }
/** /**
* @brief Removes the tags that have been verified from the multimap d_tags_awaiting_verify. * @brief Removes the tags that have been verified from the multimap d_tags_awaiting_verify.
* *
@ -1582,7 +1568,7 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size()
bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) bool osnma_msg_receiver::verify_macseq(const MACK_message& mack)
{ {
// MACSEQ verification // MACSEQ verification
d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. uint32_t GST_SFi = d_GST_Sf - 30; // time of the start of SF containing MACSEQ
std::vector<uint8_t> applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe std::vector<uint8_t> applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe
std::vector<std::string> sq1{}; std::vector<std::string> sq1{};
std::vector<std::string> sq2{}; std::vector<std::string> sq2{};
@ -1594,7 +1580,6 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack)
sq1 = it->second.sequence1; sq1 = it->second.sequence1;
sq2 = it->second.sequence2; sq2 = it->second.sequence2;
} }
// Assign relevant sequence based on subframe time // Assign relevant sequence based on subframe time
if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present.
{ {
@ -1635,10 +1620,10 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack)
// 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 + 2 * flxTags.size()); // each flx tag brings two bytes std::vector<uint8_t> m(5 + 2 * flxTags.size()); // each flx tag brings two bytes
m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag
m[1] = static_cast<uint8_t>((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless m[1] = static_cast<uint8_t>((GST_SFi & 0xFF000000) >> 24);
m[2] = static_cast<uint8_t>((d_GST_Sf & 0x00FF0000) >> 16); m[2] = static_cast<uint8_t>((GST_SFi & 0x00FF0000) >> 16);
m[3] = static_cast<uint8_t>((d_GST_Sf & 0x0000FF00) >> 8); m[3] = static_cast<uint8_t>((GST_SFi & 0x0000FF00) >> 8);
m[4] = static_cast<uint8_t>(d_GST_Sf & 0x000000FF); m[4] = static_cast<uint8_t>(GST_SFi & 0x000000FF);
// Case tags flexible - Eq. 21 ICD // Case tags flexible - Eq. 21 ICD
for (size_t i = 0; i < flxTags.size(); i++) for (size_t i = 0; i < flxTags.size(); i++)
{ {
@ -1823,7 +1808,7 @@ std::vector<MACK_tag_and_info> osnma_msg_receiver::verify_macseq_new(const MACK_
std::vector<MACK_tag_and_info> verified_tags{}; std::vector<MACK_tag_and_info> verified_tags{};
// MACSEQ verification // MACSEQ verification
d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received. uint32_t GST_Sfi = d_GST_Sf - 30; // time of the start of SF containing MACSEQ
std::vector<uint8_t> applicable_key; std::vector<uint8_t> applicable_key;
const auto key_it = d_tesla_keys.find(mack.TOW + 30); // current tesla key ie transmitted in the next subframe const auto key_it = d_tesla_keys.find(mack.TOW + 30); // current tesla key ie transmitted in the next subframe
if (key_it != d_tesla_keys.cend()) if (key_it != d_tesla_keys.cend())
@ -1891,10 +1876,10 @@ std::vector<MACK_tag_and_info> osnma_msg_receiver::verify_macseq_new(const MACK_
// 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 + 2 * flxTags.size()); // each flx tag brings two bytes std::vector<uint8_t> m(5 + 2 * flxTags.size()); // each flx tag brings two bytes
m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag
m[1] = static_cast<uint8_t>((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless m[1] = static_cast<uint8_t>((GST_Sfi & 0xFF000000) >> 24);
m[2] = static_cast<uint8_t>((d_GST_Sf & 0x00FF0000) >> 16); m[2] = static_cast<uint8_t>((GST_Sfi & 0x00FF0000) >> 16);
m[3] = static_cast<uint8_t>((d_GST_Sf & 0x0000FF00) >> 8); m[3] = static_cast<uint8_t>((GST_Sfi & 0x0000FF00) >> 8);
m[4] = static_cast<uint8_t>(d_GST_Sf & 0x000000FF); m[4] = static_cast<uint8_t>(GST_Sfi & 0x000000FF);
// Case tags flexible - Eq. 21 ICD // Case tags flexible - Eq. 21 ICD
for (size_t i = 0; i < flxTags.size(); i++) for (size_t i = 0; i < flxTags.size(); i++)
{ {

View File

@ -73,7 +73,6 @@ private:
void read_nma_header(uint8_t nma_header); void read_nma_header(uint8_t nma_header);
void read_dsm_header(uint8_t dsm_header); void read_dsm_header(uint8_t dsm_header);
void read_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg); void read_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg);
void local_time_verification(const std::shared_ptr<OSNMA_msg>& osnma_msg);
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 uint8_t& nma_header); void process_dsm_message(const std::vector<uint8_t>& dsm_msg, const uint8_t& nma_header);
void read_and_process_mack_block(const std::shared_ptr<OSNMA_msg>& osnma_msg); void read_and_process_mack_block(const std::shared_ptr<OSNMA_msg>& osnma_msg);
@ -118,35 +117,24 @@ private:
OSNMA_data d_osnma_data{}; OSNMA_data d_osnma_data{};
enum tags_to_verify uint32_t d_last_received_GST{0}; // latest GST received
{ uint32_t d_GST_Sf{}; // Scaled GST time for cryptographic computations
all, uint32_t d_GST_Rx{0}; // local GST receiver time
utc, uint32_t d_last_verified_key_GST{0}; // GST for the latest verified TESLA key
slow_eph, uint32_t d_GST_0{}; // Time of applicability GST (KROOT + 30 s)
eph, uint32_t d_GST_SIS{}; // GST coming from W6 and W5 of SIS
none
};
tags_to_verify d_tags_allowed{tags_to_verify::all};
std::time_t d_receiver_time{0};
uint32_t d_GST_Sf{}; // C: used for MACSEQ and Tesla Key verification TODO need really to be global var?
uint32_t d_last_verified_key_GST{0};
uint32_t d_GST_0{};
uint32_t d_GST_SIS{};
uint32_t d_GST_PKR_PKREV_start{}; uint32_t d_GST_PKR_PKREV_start{};
uint32_t d_GST_PKR_AM_start{}; uint32_t d_GST_PKR_AM_start{};
uint32_t d_WN{};
uint32_t d_TOW{};
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_utc{0}; // verified tag bits - timing
uint8_t const d_T_L{30}; // s RG Section 2.1 uint8_t const d_T_L{30}; // s RG Section 2.1
uint8_t const d_delta_COP{30}; // s SIS ICD Table 14
bool d_new_data{false}; bool d_new_data{false};
bool d_public_key_verified{false}; bool d_public_key_verified{false};
bool d_kroot_verified{false}; bool d_kroot_verified{false};
bool d_tesla_key_verified{false}; bool d_tesla_key_verified{false};
bool d_flag_debug{false}; bool d_flag_debug{true};
bool d_flag_hot_start{false}; bool d_flag_hot_start{false};
bool d_flag_PK_renewal{false}; bool d_flag_PK_renewal{false};
bool d_flag_PK_revocation{false}; bool d_flag_PK_revocation{false};

View File

@ -19,13 +19,37 @@
#include <iomanip> #include <iomanip>
#include <ios> #include <ios>
#include <sstream> #include <sstream>
#include <ctime> // timezone
uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const{
{ return (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF);
uint32_t GST = (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF);
return GST;
} }
uint32_t Osnma_Helper::compute_gst(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;
return compute_gst(week_number, time_of_week);
}
uint32_t Osnma_Helper::compute_gst_now()
{
std::chrono::time_point epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH) - timezone);
// auto time_utc = std::chrono::time_point_cast<std::chrono::seconds>(time).time_since_epoch();
auto duration_sec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - epoch_time_point);
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;
return compute_gst(week_number, time_of_week);
}
std::vector<uint8_t> Osnma_Helper::gst_to_uint8(uint32_t GST) const std::vector<uint8_t> Osnma_Helper::gst_to_uint8(uint32_t GST) const
{ {
@ -121,3 +145,12 @@ std::vector<uint8_t> Osnma_Helper::convert_from_hex_string(const std::string& he
return result; return result;
} }
uint32_t Osnma_Helper::get_WN(uint32_t GST)
{
return (GST & 0xFFF00000) >> 20;
}
uint32_t Osnma_Helper::get_TOW(uint32_t GST)
{
return GST & 0x000FFFFF;
}

View File

@ -18,6 +18,7 @@
#define GNSS_SDR_OSNMA_HELPER_H #define GNSS_SDR_OSNMA_HELPER_H
#include <chrono>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <vector> #include <vector>
@ -27,11 +28,18 @@ public:
Osnma_Helper() = default; Osnma_Helper() = default;
~Osnma_Helper() = default; ~Osnma_Helper() = default;
uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; uint32_t compute_gst(uint32_t WN, uint32_t TOW) const;
uint32_t compute_gst(std::tm& input);
uint32_t compute_gst_now();
uint32_t get_WN(uint32_t GST);
uint32_t get_TOW(uint32_t GST);
std::vector<uint8_t> gst_to_uint8(uint32_t GST) const; std::vector<uint8_t> gst_to_uint8(uint32_t GST) const;
std::vector<uint8_t> bytes(const std::string& binaryString) const; std::vector<uint8_t> bytes(const std::string& binaryString) const;
std::string verification_status_str(int status) const; std::string verification_status_str(int status) const;
std::string convert_to_hex_string(const std::vector<uint8_t>& vector) const; std::string convert_to_hex_string(const std::vector<uint8_t>& vector) const;
std::vector<uint8_t> convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto std::vector<uint8_t> convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto
std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0};
}; };
#endif // GNSS_SDR_OSNMA_HELPER_H #endif // GNSS_SDR_OSNMA_HELPER_H

View File

@ -252,10 +252,9 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification)
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.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.ks = 4; // TABLE 10 --> 128 bits
osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; 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_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF);
osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) 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_GST_Sf = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.
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. 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 std::vector<uint8_t> key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2