/*! * \file gnss_sdr_supl_client.c * \brief class that implements a C++ interface to external Secure User Location Protocol (SUPL) client library. * \author Javier Arribas, 2013. jarribas(at)cttc.es * * TODO: put here supl.c author info * class that implements a C++ interface to external Secure User Location Protocol (SUPL) client library. * * ----------------------------------------------------------------------------- * * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * * Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- */ #include "gnss_sdr_supl_client.h" #include "GPS_L1_CA.h" #include #include #include #include #include #include // for pow #include // for exception #include // for cerr #include // for pair #include Gnss_Sdr_Supl_Client::Gnss_Sdr_Supl_Client() { mcc = 0; mns = 0; lac = 0; ci = 0; supl_ctx_new(&ctx); assist = supl_assist_t(); server_port = 0; request = 0; } void Gnss_Sdr_Supl_Client::print_assistance() { if (assist.set & SUPL_RRLP_ASSIST_REFTIME) { fprintf(stdout, "T %ld %ld %ld %ld\n", assist.time.gps_week, assist.time.gps_tow, assist.time.stamp.tv_sec, static_cast(assist.time.stamp.tv_usec)); } if (assist.set & SUPL_RRLP_ASSIST_UTC) { fprintf(stdout, "U %d %d %d %d %d %d %d %d\n", assist.utc.a0, assist.utc.a1, assist.utc.delta_tls, assist.utc.tot, assist.utc.wnt, assist.utc.wnlsf, assist.utc.dn, assist.utc.delta_tlsf); } if (assist.set & SUPL_RRLP_ASSIST_REFLOC) { fprintf(stdout, "L %f %f %d\n", assist.pos.lat, assist.pos.lon, assist.pos.uncertainty); } if (assist.set & SUPL_RRLP_ASSIST_IONO) { fprintf(stdout, "I %d %d %d %d %d %d %d %d\n", assist.iono.a0, assist.iono.a1, assist.iono.a2, assist.iono.a3, assist.iono.b0, assist.iono.b1, assist.iono.b2, assist.iono.b3); } if (assist.cnt_eph) { int i; fprintf(stdout, "E %d\n", assist.cnt_eph); for (i = 0; i < assist.cnt_eph; i++) { struct supl_ephemeris_s* e = &assist.eph[i]; fprintf(stdout, "e %d %d %d %d %d %d %d %d %d %d", e->prn, e->delta_n, e->M0, e->A_sqrt, e->OMEGA_0, e->i0, e->w, e->OMEGA_dot, e->i_dot, e->e); fprintf(stdout, " %d %d %d %d %d %d", e->Cuc, e->Cus, e->Crc, e->Crs, e->Cic, e->Cis); fprintf(stdout, " %d %d %d %d %d %d", e->toe, e->IODC, e->toc, e->AF0, e->AF1, e->AF2); fprintf(stdout, " %d %d %d %d %d\n", e->bits, e->ura, e->health, e->tgd, e->AODA); } } if (assist.cnt_alm) { int i; fprintf(stdout, "A %d\n", assist.cnt_alm); for (i = 0; i < assist.cnt_alm; i++) { struct supl_almanac_s* a = &assist.alm[i]; fprintf(stdout, "a %d %d %d %d %d ", a->prn, a->e, a->toa, a->Ksii, a->OMEGA_dot); fprintf(stdout, "%d %d %d %d %d %d\n", a->A_sqrt, a->OMEGA_0, a->w, a->M0, a->AF0, a->AF1); } } if (assist.cnt_acq) { int i; fprintf(stdout, "Q %d %d\n", assist.cnt_acq, assist.acq_time); for (i = 0; i < assist.cnt_acq; i++) { struct supl_acquis_s* q = &assist.acq[i]; fprintf(stdout, "q %d %d %d ", q->prn, q->parts, q->doppler0); if (q->parts & SUPL_ACQUIS_DOPPLER) { fprintf(stdout, "%d %d ", q->doppler1, q->d_win); } else { fprintf(stdout, "0 0 "); } fprintf(stdout, "%d %d %d %d ", q->code_ph, q->code_ph_int, q->bit_num, q->code_ph_win); if (q->parts & SUPL_ACQUIS_ANGLE) { fprintf(stdout, "%d %d\n", q->az, q->el); } else { fprintf(stdout, "0 0\n"); } } } } int Gnss_Sdr_Supl_Client::get_assistance(int i_mcc, int i_mns, int i_lac, int i_ci) { // SET SUPL CLIENT INFORMATION // GSM CELL PARAMETERS mcc = i_mcc; mns = i_mns; lac = i_lac; ci = i_ci; if (supl_ctx_new(&ctx)) { } // clean it before using supl_set_gsm_cell(&ctx, mcc, mns, lac, ci); // PERFORM SUPL COMMUNICATION std::vector cstr(server_name.length() + 1); for (unsigned int i = 0; i != server_name.length(); ++i) { cstr[i] = static_cast(server_name[i]); } int err; ctx.p.request = request; // select assistance info request from a pre-defined set err = supl_get_assist(&ctx, cstr.data(), &assist); if (err == 0) { read_supl_data(); if (supl_ctx_free(&ctx)) { } // clean it up before leaving } else { /* * If supl_get_assist() fails, the connection remains open * and the memory/files are not released. */ supl_close(&ctx); } return err; } void Gnss_Sdr_Supl_Client::read_supl_data() { // READ REFERENCE LOCATION if (assist.set & SUPL_RRLP_ASSIST_REFLOC) { gps_ref_loc.lat = assist.pos.lat; gps_ref_loc.lon = assist.pos.lon; gps_ref_loc.uncertainty = assist.pos.uncertainty; gps_ref_loc.valid = true; } // READ REFERENCE TIME if (assist.set & SUPL_RRLP_ASSIST_REFTIME) { /* TS 44.031: GPSTOW, range 0-604799.92, resolution 0.08 sec, 23-bit presentation */ gps_time.tow = static_cast(assist.time.gps_tow) * 0.08; gps_time.week = static_cast(assist.time.gps_week); gps_time.seconds = static_cast(assist.time.stamp.tv_sec); gps_time.microseconds = static_cast(assist.time.stamp.tv_usec); gps_time.valid = true; } // READ UTC MODEL if (assist.set & SUPL_RRLP_ASSIST_UTC) { gps_utc.A0 = static_cast(assist.utc.a0) * pow(2.0, -30); gps_utc.A1 = static_cast(assist.utc.a1) * pow(2.0, -50); gps_utc.DeltaT_LS = static_cast(assist.utc.delta_tls); gps_utc.DeltaT_LSF = static_cast(assist.utc.delta_tlsf); gps_utc.tot = static_cast(assist.utc.tot) * pow(2.0, 12); gps_utc.DN = static_cast(assist.utc.dn); gps_utc.WN_T = static_cast(assist.utc.wnt); gps_utc.WN_LSF = static_cast(assist.utc.wnlsf); gps_utc.valid = true; } // READ IONOSPHERIC MODEL if (assist.set & SUPL_RRLP_ASSIST_IONO) { gps_iono.alpha0 = static_cast(assist.iono.a0) * ALPHA_0_LSB; gps_iono.alpha1 = static_cast(assist.iono.a1) * ALPHA_1_LSB; gps_iono.alpha2 = static_cast(assist.iono.a2) * ALPHA_2_LSB; gps_iono.alpha3 = static_cast(assist.iono.a3) * ALPHA_3_LSB; gps_iono.beta0 = static_cast(assist.iono.b0) * BETA_0_LSB; gps_iono.beta1 = static_cast(assist.iono.b1) * BETA_1_LSB; gps_iono.beta2 = static_cast(assist.iono.b2) * BETA_2_LSB; gps_iono.beta3 = static_cast(assist.iono.b3) * BETA_3_LSB; gps_iono.valid = true; } // READ SV ALMANAC if (assist.cnt_alm) { std::map::iterator gps_almanac_iterator; for (int i = 0; i < assist.cnt_alm; i++) { struct supl_almanac_s* a = &assist.alm[i]; // Check if the SV is present in the map gps_almanac_iterator = this->gps_almanac_map.find(a->prn); // the SV is not present in the almanac data -> insert new SV register if (gps_almanac_iterator == gps_almanac_map.end()) { Gps_Almanac gps_almanac_entry; gps_almanac_map.insert(std::pair(a->prn, gps_almanac_entry)); gps_almanac_iterator = this->gps_almanac_map.find(a->prn); } gps_almanac_iterator->second.PRN = a->prn; gps_almanac_iterator->second.af0 = static_cast(a->AF0) * pow(2.0, -20); gps_almanac_iterator->second.af1 = static_cast(a->AF1) * pow(2.0, -38); gps_almanac_iterator->second.delta_i = static_cast(a->Ksii) * pow(2.0, -19); gps_almanac_iterator->second.omega = static_cast(a->w) * pow(2.0, -23); gps_almanac_iterator->second.OMEGA_0 = static_cast(a->OMEGA_0) * pow(2.0, -23); gps_almanac_iterator->second.sqrtA = static_cast(a->A_sqrt) * pow(2.0, -11); gps_almanac_iterator->second.OMEGAdot = static_cast(a->OMEGA_dot) * pow(2.0, -38); gps_almanac_iterator->second.toa = static_cast(a->toa * pow(2.0, 12)); gps_almanac_iterator->second.ecc = static_cast(a->e) * pow(2.0, -21); gps_almanac_iterator->second.M_0 = static_cast(a->M0) * pow(2.0, -23); } } // READ SV EPHEMERIS if (assist.cnt_eph) { std::map::iterator gps_eph_iterator; for (int i = 0; i < assist.cnt_eph; i++) { struct supl_ephemeris_s* e = &assist.eph[i]; // Check if the SV is present in the map gps_eph_iterator = this->gps_ephemeris_map.find(e->prn); // the SV is not present in the assistance data -> insert new SV register if (gps_eph_iterator == gps_ephemeris_map.end()) { Gps_Ephemeris gps_eph; gps_ephemeris_map.insert(std::pair(e->prn, gps_eph)); gps_eph_iterator = this->gps_ephemeris_map.find(e->prn); } if (gps_time.valid) { gps_eph_iterator->second.WN = assist.time.gps_week; /* TS 44.031: GPSTOW, range 0-604799.92, resolution 0.08 sec, 23-bit presentation */ gps_eph_iterator->second.tow = static_cast(assist.time.gps_tow) * 0.08; } else { gps_eph_iterator->second.WN = 0; gps_eph_iterator->second.tow = 0; } gps_eph_iterator->second.PRN = e->prn; // SV navigation model gps_eph_iterator->second.code_on_L2 = e->bits; gps_eph_iterator->second.SV_accuracy = e->ura; // User Range Accuracy (URA) gps_eph_iterator->second.SV_health = e->health; gps_eph_iterator->second.IODC = static_cast(e->IODC); // miss P flag (1 bit) // miss SF1 Reserved (87 bits) gps_eph_iterator->second.TGD = static_cast(e->tgd) * T_GD_LSB; gps_eph_iterator->second.toc = static_cast(e->toc) * T_OC_LSB; gps_eph_iterator->second.af0 = static_cast(e->AF0) * A_F0_LSB; gps_eph_iterator->second.af1 = static_cast(e->AF1) * A_F1_LSB; gps_eph_iterator->second.af2 = static_cast(e->AF2) * A_F2_LSB; gps_eph_iterator->second.Crc = static_cast(e->Crc) * C_RC_LSB; gps_eph_iterator->second.delta_n = static_cast(e->delta_n) * DELTA_N_LSB; gps_eph_iterator->second.M_0 = static_cast(e->M0) * M_0_LSB; gps_eph_iterator->second.Cuc = static_cast(e->Cuc) * C_UC_LSB; gps_eph_iterator->second.ecc = static_cast(e->e) * ECCENTRICITY_LSB; gps_eph_iterator->second.Cus = static_cast(e->Cus) * C_US_LSB; gps_eph_iterator->second.sqrtA = static_cast(e->A_sqrt) * SQRT_A_LSB; gps_eph_iterator->second.toe = static_cast(e->toe) * T_OE_LSB; // miss fit interval flag (1 bit) gps_eph_iterator->second.AODO = e->AODA * AODO_LSB; gps_eph_iterator->second.Cic = static_cast(e->Cic) * C_IC_LSB; gps_eph_iterator->second.OMEGA_0 = static_cast(e->OMEGA_0) * OMEGA_0_LSB; gps_eph_iterator->second.Cis = static_cast(e->Cis) * C_IS_LSB; gps_eph_iterator->second.i_0 = static_cast(e->i0) * I_0_LSB; gps_eph_iterator->second.Crs = static_cast(e->Crs) * C_RS_LSB; gps_eph_iterator->second.omega = static_cast(e->w) * OMEGA_LSB; gps_eph_iterator->second.OMEGAdot = static_cast(e->OMEGA_dot) * OMEGA_DOT_LSB; gps_eph_iterator->second.idot = static_cast(e->i_dot) * I_DOT_LSB; } } // READ SV ACQUISITION ASSISTANCE if (assist.cnt_acq) { std::map::iterator gps_acq_iterator; for (int i = 0; i < assist.cnt_acq; i++) { struct supl_acquis_s* e = &assist.acq[i]; // Check if the SV is present in the map gps_acq_iterator = this->gps_acq_map.find(e->prn); // the SV is not present in the assistance data -> insert new SV register if (gps_acq_iterator == gps_acq_map.end()) { Gps_Acq_Assist gps_acq_assist; gps_acq_map.insert(std::pair(e->prn, gps_acq_assist)); gps_acq_iterator = this->gps_acq_map.find(e->prn); } // fill the acquisition assistance structure gps_acq_iterator->second.PRN = e->prn; gps_acq_iterator->second.tow = static_cast(assist.acq_time); gps_acq_iterator->second.Doppler0 = static_cast(e->doppler0); gps_acq_iterator->second.Doppler1 = static_cast(e->doppler1); gps_acq_iterator->second.dopplerUncertainty = static_cast(e->d_win); gps_acq_iterator->second.Code_Phase = static_cast(e->code_ph); gps_acq_iterator->second.Code_Phase_int = static_cast(e->code_ph_int); gps_acq_iterator->second.Code_Phase_window = static_cast(e->code_ph_win); gps_acq_iterator->second.Azimuth = static_cast(e->az); gps_acq_iterator->second.Elevation = static_cast(e->el); gps_acq_iterator->second.GPS_Bit_Number = static_cast(e->bit_num); } } } bool Gnss_Sdr_Supl_Client::load_ephemeris_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); gps_ephemeris_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", this->gps_ephemeris_map); LOG(INFO) << "Loaded Ephemeris map data with " << this->gps_ephemeris_map.size() << " satellites"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_ephemeris_map_xml(const std::string& file_name, std::map eph_map) { if (eph_map.empty() == false) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_ephemeris_map", eph_map); LOG(INFO) << "Saved Ephemeris map data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Ephemeris, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_gal_ephemeris_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); gal_ephemeris_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", this->gal_ephemeris_map); LOG(INFO) << "Loaded Ephemeris map data with " << this->gal_ephemeris_map.size() << " satellites"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool save_gal_ephemeris_map_xml(const std::string& file_name, std::map eph_map) { if (eph_map.empty() == false) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_gal_ephemeris_map", eph_map); LOG(INFO) << "Saved Galileo ephemeris map data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Galileo ephemeris, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_cnav_ephemeris_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); gps_cnav_ephemeris_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_cnav_ephemeris_map", this->gps_cnav_ephemeris_map); LOG(INFO) << "Loaded Ephemeris map data with " << this->gps_cnav_ephemeris_map.size() << " satellites"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool save_cnav_ephemeris_map_xml(const std::string& file_name, std::map eph_map) { if (eph_map.empty() == false) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_cnav_ephemeris_map", eph_map); LOG(INFO) << "Saved GPS CNAV ephemeris map data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save GPS CNAV ephemeris, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_gnav_ephemeris_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); gps_cnav_ephemeris_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_gnav_ephemeris_map", this->glonass_gnav_ephemeris_map); LOG(INFO) << "Loaded GLONASS ephemeris map data with " << this->gps_cnav_ephemeris_map.size() << " satellites"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool save_gnav_ephemeris_map_xml(const std::string& file_name, std::map eph_map) { if (eph_map.empty() == false) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_gnav_ephemeris_map", eph_map); LOG(INFO) << "Saved GLONASS GNAV ephemeris map data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save GLONASS GNAV ephemeris, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_utc_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_utc_model", this->gps_utc); LOG(INFO) << "Loaded UTC model data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_utc_xml(const std::string& file_name, Gps_Utc_Model& utc) { if (utc.valid) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_utc_model", utc); LOG(INFO) << "Saved GPS UTC Model data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save GPS UTC model, no valid data"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_cnav_utc_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_cnav_utc_model", this->gps_cnav_utc); LOG(INFO) << "Loaded CNAV UTC model data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_cnav_utc_xml(const std::string& file_name, Gps_CNAV_Utc_Model& utc) { if (utc.valid) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_cnav_utc_model", utc); LOG(INFO) << "Saved GPS CNAV UTC model data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save GPS CNAV UTC model, no valid data"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_gal_utc_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_gal_utc_model", this->gal_utc); LOG(INFO) << "Loaded Galileo UTC model data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_gal_utc_xml(const std::string& file_name, Galileo_Utc_Model& utc) { if (utc.flag_utc_model) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_gal_utc_model", utc); LOG(INFO) << "Saved Galileo UTC Model data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Galileo UTC model, no valid data"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_iono_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_iono_model", this->gps_iono); LOG(INFO) << "Loaded IONO model data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_iono_xml(const std::string& file_name, Gps_Iono& iono) { if (iono.valid) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_iono_model", iono); LOG(INFO) << "Saved IONO Model data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save IONO model, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_gal_iono_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_gal_iono_model", this->gal_iono); LOG(INFO) << "Loaded Galileo IONO model data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_gal_iono_xml(const std::string& file_name, Galileo_Iono& iono) { if (iono.ai0 != 0.0) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_gal_iono_model", iono); LOG(INFO) << "Saved Galileo IONO Model data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Galileo IONO model, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_gps_almanac_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); gps_almanac_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_gps_almanac_map", this->gps_almanac_map); LOG(INFO) << "Loaded GPS almanac map data with " << this->gps_almanac_map.size() << " satellites"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_gps_almanac_xml(const std::string& file_name, std::map gps_almanac_map_to_save) { if (gps_almanac_map_to_save.empty() == false) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_gps_almanac_map", gps_almanac_map_to_save); LOG(INFO) << "Saved GPS almanac data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save GPS almanac, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_gal_almanac_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); gal_almanac_map.clear(); xml >> boost::serialization::make_nvp("GNSS-SDR_gal_almanac_map", this->gal_almanac_map); } catch (std::exception& e) { // Maybe the file is from https://www.gsc-europa.eu/system-status/almanac-data ? return this->read_gal_almanac_from_gsa(file_name); } LOG(INFO) << "Loaded Galileo almanac map data with " << this->gal_almanac_map.size() << " satellites"; return true; } bool Gnss_Sdr_Supl_Client::read_gal_almanac_from_gsa(const std::string& file_name) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(file_name.c_str()); if (!result) { LOG(WARNING) << "Error loading file " << file_name << ":" << result.description(); return false; } for (pugi::xml_node almanac : doc.child("signalData") .child("body") .child("Almanacs") .children("svAlmanac")) { Galileo_Almanac gal_alm; try { uint32_t prn = static_cast(std::stoi(almanac.child_value("SVID"))); gal_alm.PRN = prn; gal_alm.toa = std::stoi(almanac.child("almanac").child_value("t0a")); gal_alm.WNa = std::stoi(almanac.child("almanac").child_value("wna")); gal_alm.IODa = std::stoi(almanac.child("almanac").child_value("iod")); gal_alm.delta_i = std::stod(almanac.child("almanac").child_value("deltai")); gal_alm.M_0 = std::stod(almanac.child("almanac").child_value("m0")); gal_alm.ecc = std::stod(almanac.child("almanac").child_value("ecc")); gal_alm.sqrtA = std::stod(almanac.child("almanac").child_value("aSqRoot")); gal_alm.OMEGA_0 = std::stod(almanac.child("almanac").child_value("omega0")); gal_alm.omega = std::stod(almanac.child("almanac").child_value("w")); gal_alm.OMEGAdot = std::stod(almanac.child("almanac").child_value("omegaDot")); gal_alm.af0 = std::stod(almanac.child("almanac").child_value("af0")); gal_alm.af1 = std::stod(almanac.child("almanac").child_value("af1")); gal_alm.E5b_HS = std::stoi(almanac.child("svINavSignalStatus").child_value("statusE5b")); gal_alm.E1B_HS = std::stoi(almanac.child("svINavSignalStatus").child_value("statusE1B")); gal_alm.E5a_HS = std::stoi(almanac.child("svFNavSignalStatus").child_value("statusE5a")); this->gal_almanac_map[static_cast(prn)] = gal_alm; } catch (const std::exception& e) { std::cerr << e.what() << '\n'; } } if (this->gal_almanac_map.empty()) { return false; } return true; } bool Gnss_Sdr_Supl_Client::save_gal_almanac_xml(const std::string& file_name, std::map galileo_almanac_map_to_save) { if (galileo_almanac_map_to_save.empty() == false) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_gal_almanac_map", galileo_almanac_map_to_save); LOG(INFO) << "Saved Galileo almanac data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Galileo almanac, map is empty"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_glo_utc_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_glo_utc_model", this->glo_gnav_utc); LOG(INFO) << "Loaded UTC model data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_glo_utc_xml(const std::string& file_name, Glonass_Gnav_Utc_Model& utc) { if (utc.valid) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_glo_utc_model", utc); LOG(INFO) << "Saved Glonass UTC Model data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Glonass UTC model, no valid data"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_ref_time_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_ref_time", this->gps_time); LOG(INFO) << "Loaded Ref Time data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_ref_time_xml(const std::string& file_name, Agnss_Ref_Time& ref_time) { if (ref_time.valid == true) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_ref_time", ref_time); LOG(INFO) << "Saved Ref Time data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Ref Time"; return false; } return true; } bool Gnss_Sdr_Supl_Client::load_ref_location_xml(const std::string& file_name) { std::ifstream ifs; try { ifs.open(file_name.c_str(), std::ifstream::binary | std::ifstream::in); boost::archive::xml_iarchive xml(ifs); xml >> boost::serialization::make_nvp("GNSS-SDR_ref_location", this->gps_ref_loc); LOG(INFO) << "Loaded Ref Location data"; } catch (std::exception& e) { LOG(WARNING) << e.what() << "File: " << file_name; return false; } return true; } bool Gnss_Sdr_Supl_Client::save_ref_location_xml(const std::string& file_name, Agnss_Ref_Location& ref_location) { if (ref_location.valid == true) { std::ofstream ofs; try { ofs.open(file_name.c_str(), std::ofstream::trunc | std::ofstream::out); boost::archive::xml_oarchive xml(ofs); xml << boost::serialization::make_nvp("GNSS-SDR_ref_location", ref_location); LOG(INFO) << "Saved Ref Location data"; } catch (std::exception& e) { LOG(WARNING) << e.what(); return false; } } else { LOG(WARNING) << "Failed to save Ref Location"; return false; } return true; }