/*!
* \file rtcm.cc
* \brief Implementation of RTCM 3.2 Standard
* \author Carles Fernandez-Prades, 2015. cfernandez(at)cttc.es
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see .
*
* -------------------------------------------------------------------------
*/
#include "rtcm.h"
#include // for std::reverse
#include // std::chrono::seconds
#include // for std::fmod
#include // for strtol
#include // for std::stringstream
#include
#include // for to_upper_copy
#include
#include
#include
#include
#include "Galileo_E1.h"
using google::LogMessage;
Rtcm::Rtcm(unsigned short port)
{
RTCM_port = port;
preamble = std::bitset<8>("11010011");
reserved_field = std::bitset<6>("000000");
rtcm_message_queue = std::make_shared< concurrent_queue >();
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), RTCM_port);
servers.emplace_back(io_service, endpoint);
server_is_running = false;
}
Rtcm::~Rtcm()
{
if(server_is_running)
{
try
{
stop_server();
}
catch(const boost::exception & e)
{
LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e);
}
catch(const std::exception & ex)
{
LOG(WARNING) << "STD exception: " << ex.what();
}
}
}
// *****************************************************************************************************
//
// TCP Server helper classes
//
// *****************************************************************************************************
void Rtcm::run_server()
{
std::cout << "Starting a TCP Server on port " << RTCM_port << std::endl;
try
{
std::thread tq([&]{ std::make_shared(io_service, rtcm_message_queue, RTCM_port)->do_read_queue(); });
tq.detach();
std::thread t([&]{ io_service.run(); });
server_is_running = true;
t.detach();
}
catch (const std::exception & e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}
void Rtcm::stop_service()
{
io_service.stop();
}
void Rtcm::stop_server()
{
std::cout << "Stopping TCP Server on port " << RTCM_port << std::endl;
rtcm_message_queue->push("Goodbye"); // this terminates tq
Rtcm::stop_service();
servers.front().close_server();
std::this_thread::sleep_for(std::chrono::seconds(1));
server_is_running = false;
}
void Rtcm::send_message(const std::string & msg)
{
rtcm_message_queue->push(msg);
}
bool Rtcm::is_server_running() const
{
return server_is_running;
}
// *****************************************************************************************************
//
// TRANSPORT LAYER AS DEFINED AT RTCM STANDARD 10403.2
//
// *****************************************************************************************************
std::string Rtcm::add_CRC (const std::string & message_without_crc) const
{
// ****** Computes Qualcomm CRC-24Q ******
boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> CRC_RTCM;
// 1) Converts the string to a vector of unsigned char:
boost::dynamic_bitset frame_bits(message_without_crc);
std::vector bytes;
boost::to_block_range(frame_bits, std::back_inserter(bytes));
std::reverse(bytes.begin(), bytes.end());
// 2) Computes CRC
CRC_RTCM.process_bytes(bytes.data(), bytes.size());
std::bitset<24> crc_frame = std::bitset<24>(CRC_RTCM.checksum());
// 3) Builds the complete message
std::string complete_message = message_without_crc + crc_frame.to_string();
return bin_to_binary_data(complete_message);
}
bool Rtcm::check_CRC(const std::string & message) const
{
boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> CRC_RTCM_CHECK;
// Convert message to binary
std::string message_bin = Rtcm::binary_data_to_bin(message);
// Check CRC
std::string crc = message_bin.substr(message_bin.length() - 24, 24);
std::bitset<24> read_crc = std::bitset<24>(crc);
std::string msg_without_crc = message_bin.substr(0, message_bin.length() - 24);
boost::dynamic_bitset frame_bits(msg_without_crc);
std::vector bytes;
boost::to_block_range(frame_bits, std::back_inserter(bytes));
std::reverse(bytes.begin(), bytes.end());
CRC_RTCM_CHECK.process_bytes(bytes.data(), bytes.size());
std::bitset<24> computed_crc = std::bitset<24>(CRC_RTCM_CHECK.checksum());
if(read_crc == computed_crc)
{
return true;
}
else
{
return false;
}
}
std::string Rtcm::bin_to_binary_data(const std::string& s) const
{
std::string s_aux;
int remainder = static_cast(std::fmod(s.length(), 8));
unsigned char c[s.length()];
unsigned int k = 0;
if (remainder != 0)
{
s_aux.assign(s, 0 , remainder);
boost::dynamic_bitset<> rembits(s_aux);
unsigned long int n = rembits.to_ulong();
c[0] = static_cast(n);
k++;
}
unsigned int start = std::max(remainder, 0);
for(unsigned int i = start; i < s.length() - 1; i = i + 8)
{
s_aux.assign(s, i, 4);
std::bitset<4> bs(s_aux);
unsigned n = bs.to_ulong();
s_aux.assign(s, i + 4 , 4);
std::bitset<4> bs2(s_aux);
unsigned n2 = bs2.to_ulong();
c[k] = static_cast(n * 16) + static_cast(n2);
k++;
}
std::string ret(c, c + k / sizeof(c[0]));
return ret;
}
std::string Rtcm::binary_data_to_bin(const std::string& s) const
{
std::string s_aux;
std::stringstream ss;
for(unsigned int i = 0; i < s.length(); i++)
{
unsigned char val = static_cast(s.at(i));
std::bitset<8> bs(val);
ss << bs;
}
s_aux = ss.str();
return s_aux;
}
std::string Rtcm::bin_to_hex(const std::string& s) const
{
std::string s_aux;
std::stringstream ss;
int remainder = static_cast(std::fmod(s.length(), 4));
if (remainder != 0)
{
s_aux.assign(s, 0 , remainder);
boost::dynamic_bitset<> rembits(s_aux);
unsigned n = rembits.to_ulong();
ss << std::hex << n;
}
unsigned int start = std::max(remainder, 0);
for(unsigned int i = start; i < s.length() - 1; i = i + 4)
{
s_aux.assign(s, i, 4);
std::bitset<4> bs(s_aux);
unsigned n = bs.to_ulong();
ss << std::hex << n;
}
return boost::to_upper_copy(ss.str());
}
std::string Rtcm::hex_to_bin(const std::string& s) const
{
std::string s_aux;
s_aux.clear();
std::stringstream ss;
ss << s;
std::string s_lower = boost::to_upper_copy(ss.str());
for(unsigned int i = 0; i < s.length(); i++)
{
unsigned long int n;
std::istringstream(s_lower.substr(i,1)) >> std::hex >> n;
std::bitset<4> bs(n);
s_aux += bs.to_string();
}
return s_aux;
}
unsigned long int Rtcm::bin_to_uint(const std::string& s) const
{
if(s.length() > 32)
{
LOG(WARNING) << "Cannot convert to a unsigned long int";
return 0;
}
unsigned long int reading = strtoul(s.c_str(), NULL, 2);
return reading;
}
long int Rtcm::bin_to_int(const std::string& s) const
{
if(s.length() > 32)
{
LOG(WARNING) << "Cannot convert to a long int";
return 0;
}
long int reading;
// Handle negative numbers
if(s.substr(0,1).compare("0"))
{
// Computing two's complement
boost::dynamic_bitset<> original_bitset(s);
original_bitset.flip();
reading = - (original_bitset.to_ulong() + 1);
}
else
{
reading = strtol(s.c_str(), NULL, 2);
}
return reading;
}
long int Rtcm::bin_to_sint(const std::string& s) const
{
if(s.length() > 32)
{
LOG(WARNING) << "Cannot convert to a long int";
return 0;
}
long int reading;
long int sign;
// Check for sign bit as defined RTCM doc
if(s.substr(0,1).compare("0") == 0)
{
sign = 1;
// Get the magnitude of the value
reading = strtol((s.substr (1)).c_str(), NULL, 2);
}
else
{
sign = -1;
// Get the magnitude of the value
reading = strtol((s.substr (1)).c_str(), NULL, 2);
}
return sign*reading;
}
// Find the sign for glonass data fields (neg = 1, pos = 0)
static inline unsigned long glo_sgn(double val)
{
if (val < 0) return 1; // If value is negative return 1
if (val==0) return 0; // Positive or equal to zero return 0
return 0;
}
double Rtcm::bin_to_double(const std::string& s) const
{
double reading;
if(s.length() > 64)
{
LOG(WARNING) << "Cannot convert to a double";
return 0;
}
long long int reading_int;
// Handle negative numbers
if(s.substr(0,1).compare("0"))
{
// Computing two's complement
boost::dynamic_bitset<> original_bitset(s);
original_bitset.flip();
std::string aux;
to_string(original_bitset, aux);
reading_int = - (strtoll(aux.c_str(), NULL, 2) + 1);
}
else
{
reading_int = strtoll(s.c_str(), NULL, 2);
}
reading = static_cast(reading_int);
return reading;
}
unsigned long int Rtcm::hex_to_uint(const std::string& s) const
{
if(s.length() > 32)
{
LOG(WARNING) << "Cannot convert to a unsigned long int";
return 0;
}
unsigned long int reading = strtoul(s.c_str(), NULL, 16);
return reading;
}
long int Rtcm::hex_to_int(const std::string& s) const
{
if(s.length() > 32)
{
LOG(WARNING) << "Cannot convert to a long int";
return 0;
}
long int reading = strtol(s.c_str(), NULL, 16);
return reading;
}
std::string Rtcm::build_message(const std::string & data) const
{
unsigned int msg_length_bits = data.length();
unsigned int msg_length_bytes = std::ceil(static_cast(msg_length_bits) / 8.0);
std::bitset<10> message_length = std::bitset<10>(msg_length_bytes);
unsigned int zeros_to_fill = 8 * msg_length_bytes - msg_length_bits;
std::string b(zeros_to_fill, '0');
std::string msg_content = data + b;
std::string msg_without_crc = preamble.to_string() +
reserved_field.to_string() +
message_length.to_string() +
msg_content;
return Rtcm::add_CRC(msg_without_crc);
}
// *****************************************************************************************************
//
// MESSAGES AS DEFINED AT RTCM STANDARD 10403.2
//
// *****************************************************************************************************
// ********************************************************
//
// MESSAGE TYPE 1001 (GPS L1 OBSERVATIONS)
//
// ********************************************************
std::bitset<64> Rtcm::get_MT1001_4_header(unsigned int msg_number, double obs_time, const std::map & observables,
unsigned int ref_id, unsigned int smooth_int, bool sync_flag, bool divergence_free)
{
unsigned int reference_station_id = ref_id; // Max: 4095
const std::map observables_ = observables;
bool synchronous_GNSS_flag = sync_flag;
bool divergence_free_smoothing_indicator = divergence_free;
unsigned int smoothing_interval = smooth_int;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF003(reference_station_id);
Rtcm::set_DF004(obs_time);
Rtcm::set_DF005(synchronous_GNSS_flag);
Rtcm::set_DF006(observables_);
Rtcm::set_DF007(divergence_free_smoothing_indicator);
Rtcm::set_DF008(smoothing_interval);
std::string header = DF002.to_string() +
DF003.to_string() +
DF004.to_string() +
DF005.to_string() +
DF006.to_string() +
DF007.to_string() +
DF008.to_string();
std::bitset<64> header_msg(header);
return header_msg;
}
std::bitset<58> Rtcm::get_MT1001_sat_content(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF009(gnss_synchro);
Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF011(gnss_synchro);
Rtcm::set_DF012(gnss_synchro);
Rtcm::set_DF013(eph, obs_time, gnss_synchro);
std::string content = DF009.to_string() +
DF010.to_string() +
DF011.to_string() +
DF012.to_string() +
DF013.to_string();
std::bitset<58> content_msg(content);
return content_msg;
}
std::string Rtcm::print_MT1001(const Gps_Ephemeris & gps_eph, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get a map with GPS L1 only observations
std::map observablesL1;
std::map::const_iterator observables_iter;
for(observables_iter = observables.cbegin();
observables_iter != observables.cend();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("G") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
std::bitset<64> header = Rtcm::get_MT1001_4_header(1001, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(observables_iter = observablesL1.cbegin();
observables_iter != observablesL1.cend();
observables_iter++)
{
std::bitset<58> content = Rtcm::get_MT1001_sat_content(gps_eph, obs_time, observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
// ********************************************************
//
// MESSAGE TYPE 1002 (EXTENDED GPS L1 OBSERVATIONS)
//
// ********************************************************
std::string Rtcm::print_MT1002(const Gps_Ephemeris & gps_eph, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get a map with GPS L1 only observations
std::map observablesL1;
std::map::const_iterator observables_iter;
for(observables_iter = observables.cbegin();
observables_iter != observables.cend();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("G") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
std::bitset<64> header = Rtcm::get_MT1001_4_header(1002, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(observables_iter = observablesL1.cbegin();
observables_iter != observablesL1.cend();
observables_iter++)
{
std::bitset<74> content = Rtcm::get_MT1002_sat_content(gps_eph, obs_time, observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
std::bitset<74> Rtcm::get_MT1002_sat_content(const Gps_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF009(gnss_synchro);
Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF011(gnss_synchro);
Rtcm::set_DF012(gnss_synchro);
Rtcm::set_DF013(eph, obs_time, gnss_synchro);
std::string content = DF009.to_string() +
DF010.to_string() +
DF011.to_string() +
DF012.to_string() +
DF013.to_string() +
DF014.to_string() +
DF015.to_string();
std::bitset<74> content_msg(content);
return content_msg;
}
// ********************************************************
//
// MESSAGE TYPE 1003 (GPS L1 & L2 OBSERVATIONS)
//
// ********************************************************
std::string Rtcm::print_MT1003(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get maps with GPS L1 and L2 observations
std::map observablesL1;
std::map observablesL2;
std::map::const_iterator observables_iter;
std::map::const_iterator observables_iter2;
for(observables_iter = observables.cbegin();
observables_iter != observables.cend();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("G") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
if((system_.compare("G") == 0) && (sig_.compare("2S") == 0))
{
observablesL2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
// Get common observables
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables;
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter;
std::map observablesL1_with_L2;
for(observables_iter = observablesL1.cbegin();
observables_iter != observablesL1.cend();
observables_iter++)
{
unsigned int prn_ = observables_iter->second.PRN;
for(observables_iter2 = observablesL2.cbegin();
observables_iter2 != observablesL2.cend();
observables_iter2++)
{
if(observables_iter2->second.PRN == prn_)
{
std::pair p;
Gnss_Synchro pr1 = observables_iter->second;
Gnss_Synchro pr2 = observables_iter2->second;
p = std::make_pair(pr1, pr2);
common_observables.push_back(p);
observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
}
std::bitset<64> header = Rtcm::get_MT1001_4_header(1003, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(common_observables_iter = common_observables.cbegin();
common_observables_iter != common_observables.cend();
common_observables_iter++)
{
std::bitset<101> content = Rtcm::get_MT1003_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
std::bitset<101> Rtcm::get_MT1003_sat_content(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF009(gnss_synchroL1);
Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF011(gnss_synchroL1);
Rtcm::set_DF012(gnss_synchroL1);
Rtcm::set_DF013(ephL1, obs_time, gnss_synchroL1);
std::bitset<2> DF016_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y
Rtcm::set_DF017(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF018(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF019(ephL2, obs_time, gnss_synchroL2);
std::string content = DF009.to_string() +
DF010.to_string() +
DF011.to_string() +
DF012.to_string() +
DF013.to_string() +
DF016_.to_string() +
DF017.to_string() +
DF018.to_string() +
DF019.to_string();
std::bitset<101> content_msg(content);
return content_msg;
}
// ******************************************************************
//
// MESSAGE TYPE 1004 (EXTENDED GPS L1 & L2 OBSERVATIONS)
//
// ******************************************************************
std::string Rtcm::print_MT1004(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get maps with GPS L1 and L2 observations
std::map observablesL1;
std::map observablesL2;
std::map::const_iterator observables_iter;
std::map::const_iterator observables_iter2;
for(observables_iter = observables.cbegin();
observables_iter != observables.cend();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("G") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
if((system_.compare("G") == 0) && (sig_.compare("2S") == 0))
{
observablesL2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
// Get common observables
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables;
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter;
std::map observablesL1_with_L2;
for(observables_iter = observablesL1.cbegin();
observables_iter != observablesL1.cend();
observables_iter++)
{
unsigned int prn_ = observables_iter->second.PRN;
for(observables_iter2 = observablesL2.cbegin();
observables_iter2 != observablesL2.cend();
observables_iter2++)
{
if(observables_iter2->second.PRN == prn_)
{
std::pair p;
Gnss_Synchro pr1 = observables_iter->second;
Gnss_Synchro pr2 = observables_iter2->second;
p = std::make_pair(pr1, pr2);
common_observables.push_back(p);
observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
}
std::bitset<64> header = Rtcm::get_MT1001_4_header(1004, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(common_observables_iter = common_observables.cbegin();
common_observables_iter != common_observables.cend();
common_observables_iter++)
{
std::bitset<125> content = Rtcm::get_MT1004_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
std::bitset<125> Rtcm::get_MT1004_sat_content(const Gps_Ephemeris & ephL1, const Gps_CNAV_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF009(gnss_synchroL1);
Rtcm::set_DF010(code_indicator); // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF011(gnss_synchroL1);
Rtcm::set_DF012(gnss_synchroL1);
Rtcm::set_DF013(ephL1, obs_time, gnss_synchroL1);
Rtcm::set_DF014(gnss_synchroL1);
Rtcm::set_DF015(gnss_synchroL1);
std::bitset<2> DF016_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y
Rtcm::set_DF017(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF018(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF019(ephL2, obs_time, gnss_synchroL2);
Rtcm::set_DF020(gnss_synchroL2);
std::string content = DF009.to_string() +
DF010.to_string() +
DF011.to_string() +
DF012.to_string() +
DF013.to_string() +
DF014.to_string() +
DF015.to_string() +
DF016_.to_string() +
DF017.to_string() +
DF018.to_string() +
DF019.to_string() +
DF020.to_string();
std::bitset<125> content_msg(content);
return content_msg;
}
// ********************************************************
//
// MESSAGE TYPE 1005 (STATION DESCRIPTION)
//
// ********************************************************
/* Stationary Antenna Reference Point, No Height Information
* Reference Station Id = 2003
GPS Service supported, but not GLONASS or Galileo
ARP ECEF-X = 1114104.5999 meters
ARP ECEF-Y = -4850729.7108 meters
ARP ECEF-Z = 3975521.4643 meters
Expected output: D3 00 13 3E D7 D3 02 02 98 0E DE EF 34 B4 BD 62
AC 09 41 98 6F 33 36 0B 98
*/
std::bitset<152> Rtcm::get_MT1005_test ()
{
unsigned int mt1005 = 1005;
unsigned int reference_station_id = 2003; // Max: 4095
double ECEF_X = 1114104.5999; // units: m
double ECEF_Y = -4850729.7108; // units: m
double ECEF_Z = 3975521.4643; // units: m
std::bitset<1> DF001_;
Rtcm::set_DF002(mt1005);
Rtcm::set_DF003(reference_station_id);
Rtcm::set_DF021();
Rtcm::set_DF022(true); // GPS
Rtcm::set_DF023(false); // Glonass
Rtcm::set_DF024(false); // Galileo
DF141 = std::bitset<1>("0"); // 0: Real, physical reference station
DF001_ = std::bitset<1>("0"); // Reserved, set to 0
Rtcm::set_DF025(ECEF_X);
DF142 = std::bitset<1>("0"); // Single Receiver Oscillator Indicator
Rtcm::set_DF026(ECEF_Y);
DF364 = std::bitset<2>("00"); // Quarter Cycle Indicator
Rtcm::set_DF027(ECEF_Z);
std::string message = DF002.to_string() +
DF003.to_string() +
DF021.to_string() +
DF022.to_string() +
DF023.to_string() +
DF024.to_string() +
DF141.to_string() +
DF025.to_string() +
DF142.to_string() +
DF001_.to_string() +
DF026.to_string() +
DF364.to_string() +
DF027.to_string() ;
std::bitset<152> test_msg(message);
return test_msg;
}
std::string Rtcm::print_MT1005( unsigned int ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, unsigned int quarter_cycle_indicator)
{
unsigned int msg_number = 1005;
std::bitset<1> DF001_;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF003(ref_id);
Rtcm::set_DF021();
Rtcm::set_DF022(gps);
Rtcm::set_DF023(glonass);
Rtcm::set_DF024(galileo);
DF141 = std::bitset<1>(non_physical);
DF001_ = std::bitset<1>("0");
Rtcm::set_DF025(ecef_x);
DF142 = std::bitset<1>(single_oscillator);
Rtcm::set_DF026(ecef_y);
DF364 = std::bitset<2>(quarter_cycle_indicator);
Rtcm::set_DF027(ecef_z);
std::string data = DF002.to_string() +
DF003.to_string() +
DF021.to_string() +
DF022.to_string() +
DF023.to_string() +
DF024.to_string() +
DF141.to_string() +
DF025.to_string() +
DF142.to_string() +
DF001_.to_string() +
DF026.to_string() +
DF364.to_string() +
DF027.to_string() ;
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
int Rtcm::read_MT1005(const std::string & message, unsigned int & ref_id, double & ecef_x, double & ecef_y, double & ecef_z, bool & gps, bool & glonass, bool & galileo)
{
// Convert message to binary
std::string message_bin = Rtcm::binary_data_to_bin(message);
if(!Rtcm::check_CRC(message) )
{
LOG(WARNING) << " Bad CRC detected in RTCM message MT1005";
return 1;
}
// Check than the message number is correct
unsigned int preamble_length = 8;
unsigned int reserved_field_length = 6;
unsigned int index = preamble_length + reserved_field_length;
unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10)));
index += 10;
if (read_message_length != 19)
{
LOG(WARNING) << " Message MT1005 with wrong length (19 bytes expected, " << read_message_length << " received)";
return 1;
}
unsigned int msg_number = 1005;
Rtcm::set_DF002(msg_number);
std::bitset<12> read_msg_number(message_bin.substr(index, 12));
index += 12;
if (DF002 != read_msg_number)
{
LOG(WARNING) << " This is not a MT1005 message";
return 1;
}
ref_id = Rtcm::bin_to_uint(message_bin.substr(index, 12));
index += 12;
index += 6; // ITRF year
gps = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
glonass = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
galileo = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
index += 1; // ref_station_indicator
ecef_x = Rtcm::bin_to_double(message_bin.substr(index, 38)) / 10000.0;
index += 38;
index += 1; // single rx oscillator
index += 1; // reserved
ecef_y = Rtcm::bin_to_double(message_bin.substr(index, 38)) / 10000.0;
index += 38;
index += 2; // quarter cycle indicator
ecef_z = Rtcm::bin_to_double(message_bin.substr(index, 38)) / 10000.0;
return 0;
}
std::string Rtcm::print_MT1005_test()
{
std::bitset<152> mt1005 = get_MT1005_test();
return Rtcm::build_message(mt1005.to_string());
}
// ********************************************************
//
// MESSAGE TYPE 1006 (STATION DESCRIPTION PLUS HEIGHT INFORMATION)
//
// ********************************************************
std::string Rtcm::print_MT1006(unsigned int ref_id, double ecef_x, double ecef_y, double ecef_z, bool gps, bool glonass, bool galileo, bool non_physical, bool single_oscillator, unsigned int quarter_cycle_indicator, double height)
{
unsigned int msg_number = 1006;
std::bitset<1> DF001_;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF003(ref_id);
Rtcm::set_DF021();
Rtcm::set_DF022(gps);
Rtcm::set_DF023(glonass);
Rtcm::set_DF024(galileo);
DF141 = std::bitset<1>(non_physical);
DF001_ = std::bitset<1>("0");
Rtcm::set_DF025(ecef_x);
DF142 = std::bitset<1>(single_oscillator);
Rtcm::set_DF026(ecef_y);
DF364 = std::bitset<2>(quarter_cycle_indicator);
Rtcm::set_DF027(ecef_z);
Rtcm::set_DF028(height);
std::string data = DF002.to_string() +
DF003.to_string() +
DF021.to_string() +
DF022.to_string() +
DF023.to_string() +
DF024.to_string() +
DF141.to_string() +
DF025.to_string() +
DF142.to_string() +
DF001_.to_string() +
DF026.to_string() +
DF364.to_string() +
DF027.to_string() +
DF028.to_string();
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
// ********************************************************
//
// MESSAGE TYPE 1008 (ANTENNA DESCRIPTOR & SERIAL NUMBER)
//
// ********************************************************
std::string Rtcm::print_MT1008(unsigned int ref_id, const std::string & antenna_descriptor, unsigned int antenna_setup_id, const std::string & antenna_serial_number)
{
unsigned int msg_number = 1008;
std::bitset<12> DF002_ = std::bitset<12>(msg_number);
Rtcm::set_DF003(ref_id);
std::string ant_descriptor = antenna_descriptor;
unsigned int len = ant_descriptor.length();
if (len > 31)
{
ant_descriptor = ant_descriptor.substr(0, 31);
len = 31;
}
DF029 = std::bitset<8>(len);
std::string DF030_str_;
for(auto it = ant_descriptor.cbegin(); it != ant_descriptor.cend(); it++)
{
char c = *it;
std::bitset<8> character = std::bitset<8>(c);
DF030_str_ += character.to_string();
}
Rtcm::set_DF031(antenna_setup_id);
std::string ant_sn(antenna_serial_number);
unsigned int len2 = ant_sn.length();
if (len2 > 31)
{
ant_sn = ant_sn.substr(0, 31);
len2 = 31;
}
DF032 = std::bitset<8>(len2);
std::string DF033_str_;
for(auto it = ant_sn.cbegin(); it != ant_sn.cend(); it++)
{
char c = *it;
std::bitset<8> character = std::bitset<8>(c);
DF033_str_ += character.to_string();
}
std::string data = DF002_.to_string() +
DF003.to_string() +
DF029.to_string() +
DF030_str_ +
DF031.to_string() +
DF032.to_string() +
DF033_str_;
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
// ********************************************************
//
// MESSAGE TYPE 1009 (GLONASS L1 Basic RTK Observables)
//
// ********************************************************
std::bitset<61> Rtcm::get_MT1009_12_header(unsigned int msg_number, double obs_time, const std::map & observables,
unsigned int ref_id, unsigned int smooth_int, bool sync_flag, bool divergence_free)
{
unsigned int reference_station_id = ref_id; // Max: 4095
const std::map observables_ = observables;
bool synchronous_GNSS_flag = sync_flag;
bool divergence_free_smoothing_indicator = divergence_free;
unsigned int smoothing_interval = smooth_int;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF003(reference_station_id);
Rtcm::set_DF034(obs_time);
Rtcm::set_DF005(synchronous_GNSS_flag);
Rtcm::set_DF035(observables_);
Rtcm::set_DF036(divergence_free_smoothing_indicator);
Rtcm::set_DF037(smoothing_interval);
std::string header = DF002.to_string() +
DF003.to_string() +
DF034.to_string() +
DF005.to_string() +
DF035.to_string() +
DF036.to_string() +
DF037.to_string();
std::bitset<61> header_msg(header);
return header_msg;
}
std::bitset<64> Rtcm::get_MT1009_sat_content(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF038(gnss_synchro);
Rtcm::set_DF039(code_indicator);
Rtcm::set_DF040(eph.i_satellite_freq_channel);
Rtcm::set_DF041(gnss_synchro);
Rtcm::set_DF042(gnss_synchro);
Rtcm::set_DF043(eph, obs_time, gnss_synchro);
std::string content = DF038.to_string() +
DF039.to_string() +
DF040.to_string() +
DF041.to_string() +
DF042.to_string() +
DF043.to_string();
std::bitset<64> content_msg(content);
return content_msg;
}
std::string Rtcm::print_MT1009(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get a map with GLONASS L1 only observations
std::map observablesL1;
std::map::const_iterator observables_iter;
for(observables_iter = observables.begin();
observables_iter != observables.end();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("R") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
std::bitset<61> header = Rtcm::get_MT1009_12_header(1009, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(observables_iter = observablesL1.begin();
observables_iter != observablesL1.end();
observables_iter++)
{
std::bitset<64> content = Rtcm::get_MT1009_sat_content(glonass_gnav_eph, obs_time, observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
// ********************************************************
//
// MESSAGE TYPE 1010 (EXTENDED GLONASS L1 OBSERVATIONS)
//
// ********************************************************
std::string Rtcm::print_MT1010(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get a map with GPS L1 only observations
std::map observablesL1;
std::map::const_iterator observables_iter;
for(observables_iter = observables.begin();
observables_iter != observables.end();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("R") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
std::bitset<61> header = Rtcm::get_MT1009_12_header(1010, obs_time, observablesL1, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(observables_iter = observablesL1.begin();
observables_iter != observablesL1.end();
observables_iter++)
{
std::bitset<79> content = Rtcm::get_MT1010_sat_content(glonass_gnav_eph, obs_time, observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
std::bitset<79> Rtcm::get_MT1010_sat_content(const Glonass_Gnav_Ephemeris & eph, double obs_time, const Gnss_Synchro & gnss_synchro)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF038(gnss_synchro);
Rtcm::set_DF039(code_indicator);
Rtcm::set_DF040(eph.i_satellite_freq_channel);
Rtcm::set_DF041(gnss_synchro);
Rtcm::set_DF042(gnss_synchro);
Rtcm::set_DF043(eph, obs_time, gnss_synchro);
Rtcm::set_DF044(gnss_synchro);
Rtcm::set_DF045(gnss_synchro);
std::string content = DF038.to_string() +
DF039.to_string() +
DF040.to_string() +
DF041.to_string() +
DF042.to_string() +
DF043.to_string() +
DF044.to_string() +
DF045.to_string();
std::bitset<79> content_msg(content);
return content_msg;
}
// ********************************************************
//
// MESSAGE TYPE 1011 (GLONASS L1 & L2 OBSERVATIONS)
//
// ********************************************************
std::string Rtcm::print_MT1011(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get maps with GPS L1 and L2 observations
std::map observablesL1;
std::map observablesL2;
std::map::const_iterator observables_iter;
std::map::const_iterator observables_iter2;
for(observables_iter = observables.begin();
observables_iter != observables.end();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("R") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
if((system_.compare("R") == 0) && (sig_.compare("2C") == 0))
{
observablesL2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
// Get common observables
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables;
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter;
std::map observablesL1_with_L2;
for(observables_iter = observablesL1.begin();
observables_iter != observablesL1.end();
observables_iter++)
{
unsigned int prn_ = observables_iter->second.PRN;
for(observables_iter2 = observablesL2.begin();
observables_iter2 != observablesL2.end();
observables_iter2++)
{
if(observables_iter2->second.PRN == prn_)
{
std::pair p;
Gnss_Synchro pr1 = observables_iter->second;
Gnss_Synchro pr2 = observables_iter2->second;
p = std::make_pair(pr1, pr2);
common_observables.push_back(p);
observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
}
std::bitset<61> header = Rtcm::get_MT1009_12_header(1011, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(common_observables_iter = common_observables.begin();
common_observables_iter != common_observables.end();
common_observables_iter++)
{
std::bitset<107> content = Rtcm::get_MT1011_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
std::bitset<107> Rtcm::get_MT1011_sat_content(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF038(gnss_synchroL1);
Rtcm::set_DF039(code_indicator);
Rtcm::set_DF040(ephL1.i_satellite_freq_channel);
Rtcm::set_DF041(gnss_synchroL1);
Rtcm::set_DF042(gnss_synchroL1);
Rtcm::set_DF043(ephL1, obs_time, gnss_synchroL1);
std::bitset<2> DF046_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y
Rtcm::set_DF047(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF048(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF049(ephL2, obs_time, gnss_synchroL2);
std::string content = DF038.to_string() +
DF039.to_string() +
DF040.to_string() +
DF041.to_string() +
DF042.to_string() +
DF043.to_string() +
DF046_.to_string() +
DF047.to_string() +
DF048.to_string() +
DF049.to_string();
std::bitset<107> content_msg(content);
return content_msg;
}
// ******************************************************************
//
// MESSAGE TYPE 1004 (EXTENDED GLONASS L1 & L2 OBSERVATIONS)
//
// ******************************************************************
std::string Rtcm::print_MT1012(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const std::map & observables, unsigned short station_id)
{
unsigned int ref_id = static_cast(station_id);
unsigned int smooth_int = 0;
bool sync_flag = false;
bool divergence_free = false;
//Get maps with GLONASS L1 and L2 observations
std::map observablesL1;
std::map observablesL2;
std::map::const_iterator observables_iter;
std::map::const_iterator observables_iter2;
for(observables_iter = observables.begin();
observables_iter != observables.end();
observables_iter++)
{
std::string system_(&observables_iter->second.System, 1);
std::string sig_(observables_iter->second.Signal);
if((system_.compare("R") == 0) && (sig_.compare("1C") == 0))
{
observablesL1.insert(std::pair(observables_iter->first, observables_iter->second));
}
if((system_.compare("R") == 0) && (sig_.compare("2C") == 0))
{
observablesL2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
// Get common observables
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > > common_observables;
std::vector< std::pair< Gnss_Synchro, Gnss_Synchro > >::const_iterator common_observables_iter;
std::map observablesL1_with_L2;
for(observables_iter = observablesL1.begin();
observables_iter != observablesL1.end();
observables_iter++)
{
unsigned int prn_ = observables_iter->second.PRN;
for(observables_iter2 = observablesL2.begin();
observables_iter2 != observablesL2.end();
observables_iter2++)
{
if(observables_iter2->second.PRN == prn_)
{
std::pair p;
Gnss_Synchro pr1 = observables_iter->second;
Gnss_Synchro pr2 = observables_iter2->second;
p = std::make_pair(pr1, pr2);
common_observables.push_back(p);
observablesL1_with_L2.insert(std::pair(observables_iter->first, observables_iter->second));
}
}
}
std::bitset<61> header = Rtcm::get_MT1009_12_header(1012, obs_time, observablesL1_with_L2, ref_id, smooth_int, sync_flag, divergence_free);
std::string data = header.to_string();
for(common_observables_iter = common_observables.begin();
common_observables_iter != common_observables.end();
common_observables_iter++)
{
std::bitset<130> content = Rtcm::get_MT1012_sat_content(ephL1, ephL2, obs_time, common_observables_iter->first, common_observables_iter->second);
data += content.to_string();
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
std::bitset<130> Rtcm::get_MT1012_sat_content(const Glonass_Gnav_Ephemeris & ephL1, const Glonass_Gnav_Ephemeris & ephL2, double obs_time, const Gnss_Synchro & gnss_synchroL1, const Gnss_Synchro & gnss_synchroL2)
{
bool code_indicator = false; // code indicator 0: C/A code 1: P(Y) code direct
Rtcm::set_DF038(gnss_synchroL1);
Rtcm::set_DF039(code_indicator);
Rtcm::set_DF040(ephL1.i_satellite_freq_channel);
Rtcm::set_DF041(gnss_synchroL1);
Rtcm::set_DF042(gnss_synchroL1);
Rtcm::set_DF043(ephL1, obs_time, gnss_synchroL1);
Rtcm::set_DF044(gnss_synchroL1);
Rtcm::set_DF045(gnss_synchroL1);
std::bitset<2> DF046_ = std::bitset<2>(0); // code indicator 0: C/A or L2C code 1: P(Y) code direct 2:P(Y) code cross-correlated 3: Correlated P/Y
Rtcm::set_DF047(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF048(gnss_synchroL1, gnss_synchroL2);
Rtcm::set_DF049(ephL2, obs_time, gnss_synchroL2);
Rtcm::set_DF050(gnss_synchroL2);
std::string content = DF038.to_string() +
DF039.to_string() +
DF040.to_string() +
DF041.to_string() +
DF042.to_string() +
DF043.to_string() +
DF044.to_string() +
DF045.to_string() +
DF046_.to_string() +
DF047.to_string() +
DF048.to_string() +
DF049.to_string() +
DF050.to_string();
std::bitset<130> content_msg(content);
return content_msg;
}
// ********************************************************
//
// MESSAGE TYPE 1019 (GPS EPHEMERIS)
//
// ********************************************************
std::string Rtcm::print_MT1019(const Gps_Ephemeris & gps_eph)
{
unsigned int msg_number = 1019;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF009(gps_eph);
Rtcm::set_DF076(gps_eph);
Rtcm::set_DF077(gps_eph);
Rtcm::set_DF078(gps_eph);
Rtcm::set_DF079(gps_eph);
Rtcm::set_DF071(gps_eph);
Rtcm::set_DF081(gps_eph);
Rtcm::set_DF082(gps_eph);
Rtcm::set_DF083(gps_eph);
Rtcm::set_DF084(gps_eph);
Rtcm::set_DF085(gps_eph);
Rtcm::set_DF086(gps_eph);
Rtcm::set_DF087(gps_eph);
Rtcm::set_DF088(gps_eph);
Rtcm::set_DF089(gps_eph);
Rtcm::set_DF090(gps_eph);
Rtcm::set_DF091(gps_eph);
Rtcm::set_DF092(gps_eph);
Rtcm::set_DF093(gps_eph);
Rtcm::set_DF094(gps_eph);
Rtcm::set_DF095(gps_eph);
Rtcm::set_DF096(gps_eph);
Rtcm::set_DF097(gps_eph);
Rtcm::set_DF098(gps_eph);
Rtcm::set_DF099(gps_eph);
Rtcm::set_DF100(gps_eph);
Rtcm::set_DF101(gps_eph);
Rtcm::set_DF102(gps_eph);
Rtcm::set_DF103(gps_eph);
Rtcm::set_DF137(gps_eph);
std::string data;
data.clear();
data = DF002.to_string() +
DF009.to_string() +
DF076.to_string() +
DF077.to_string() +
DF078.to_string() +
DF079.to_string() +
DF071.to_string() +
DF081.to_string() +
DF082.to_string() +
DF083.to_string() +
DF084.to_string() +
DF085.to_string() +
DF086.to_string() +
DF087.to_string() +
DF088.to_string() +
DF089.to_string() +
DF090.to_string() +
DF091.to_string() +
DF092.to_string() +
DF093.to_string() +
DF094.to_string() +
DF095.to_string() +
DF096.to_string() +
DF097.to_string() +
DF098.to_string() +
DF099.to_string() +
DF100.to_string() +
DF101.to_string() +
DF102.to_string() +
DF103.to_string() +
DF137.to_string();
if (data.length() != 488)
{
LOG(WARNING) << "Bad-formatted RTCM MT1019 (488 bits expected, found " << data.length() << ")";
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
int Rtcm::read_MT1019(const std::string & message, Gps_Ephemeris & gps_eph)
{
// Convert message to binary
std::string message_bin = Rtcm::binary_data_to_bin(message);
if(!Rtcm::check_CRC(message) )
{
LOG(WARNING) << " Bad CRC detected in RTCM message MT1019";
return 1;
}
unsigned int preamble_length = 8;
unsigned int reserved_field_length = 6;
unsigned int index = preamble_length + reserved_field_length;
unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10)));
index += 10;
if (read_message_length != 61)
{
LOG(WARNING) << " Message MT1019 seems too long (61 bytes expected, " << read_message_length << " received)";
return 1;
}
// Check than the message number is correct
unsigned int read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12));
index += 12;
if (1019 != read_msg_number)
{
LOG(WARNING) << " This is not a MT1019 message";
return 1;
}
// Fill Gps Ephemeris with message data content
gps_eph.i_satellite_PRN = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6)));
index += 6;
gps_eph.i_GPS_week = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10)));
index += 10;
gps_eph.i_SV_accuracy = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 4)));
index += 4;
gps_eph.i_code_on_L2 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2)));
index += 2;
gps_eph.d_IDOT = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 14))) * I_DOT_LSB;
index += 14;
gps_eph.d_IODE_SF2 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 8)));
gps_eph.d_IODE_SF3 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 8)));
index += 8;
gps_eph.d_Toc = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 16))) * T_OC_LSB;
index += 16;
gps_eph.d_A_f2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 8))) * A_F2_LSB;
index += 8;
gps_eph.d_A_f1 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * A_F1_LSB;
index += 16;
gps_eph.d_A_f0 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 22))) * A_F0_LSB;
index += 22;
gps_eph.d_IODC = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10)));
index += 10;
gps_eph.d_Crs = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_RS_LSB;
index += 16;
gps_eph.d_Delta_n = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * DELTA_N_LSB;
index += 16;
gps_eph.d_M_0 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * M_0_LSB;
index += 32;
gps_eph.d_Cuc = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_UC_LSB;
index += 16;
gps_eph.d_e_eccentricity = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 32))) * E_LSB;
index += 32;
gps_eph.d_Cus = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_US_LSB;
index += 16;
gps_eph.d_sqrt_A = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 32))) * SQRT_A_LSB;
index += 32;
gps_eph.d_Toe = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 16))) * T_OE_LSB;
index += 16;
gps_eph.d_Cic = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_IC_LSB;
index += 16;
gps_eph.d_OMEGA0 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * OMEGA_0_LSB;
index += 32;
gps_eph.d_Cis = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_IS_LSB;
index += 16;
gps_eph.d_i_0 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * I_0_LSB;
index += 32;
gps_eph.d_Crc = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_RC_LSB;
index += 16;
gps_eph.d_OMEGA = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * OMEGA_LSB;
index += 32;
gps_eph.d_OMEGA_DOT = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 24))) * OMEGA_DOT_LSB;
index += 24;
gps_eph.d_TGD = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 8))) * T_GD_LSB;
index += 8;
gps_eph.i_SV_health = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6)));
index += 6;
gps_eph.b_L2_P_data_flag = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
gps_eph.b_fit_interval_flag = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
return 0;
}
// ********************************************************
//
// MESSAGE TYPE 1020 (GLONASS EPHEMERIS)
//
// ********************************************************
std::string Rtcm::print_MT1020(const Glonass_Gnav_Ephemeris & glonass_gnav_eph, const Glonass_Gnav_Utc_Model & glonass_gnav_utc_model)
{
unsigned int msg_number = 1020;
unsigned int glonass_gnav_alm_health = 0;
unsigned int glonass_gnav_alm_health_ind = 0;
unsigned int fifth_str_additional_data_ind = 1;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF038(glonass_gnav_eph);
Rtcm::set_DF040(glonass_gnav_eph);
Rtcm::set_DF104(glonass_gnav_alm_health);
Rtcm::set_DF105(glonass_gnav_alm_health_ind);
Rtcm::set_DF106(glonass_gnav_eph);
Rtcm::set_DF107(glonass_gnav_eph);
Rtcm::set_DF108(glonass_gnav_eph);
Rtcm::set_DF109(glonass_gnav_eph);
Rtcm::set_DF110(glonass_gnav_eph);
Rtcm::set_DF111(glonass_gnav_eph);
Rtcm::set_DF112(glonass_gnav_eph);
Rtcm::set_DF113(glonass_gnav_eph);
Rtcm::set_DF114(glonass_gnav_eph);
Rtcm::set_DF115(glonass_gnav_eph);
Rtcm::set_DF116(glonass_gnav_eph);
Rtcm::set_DF117(glonass_gnav_eph);
Rtcm::set_DF118(glonass_gnav_eph);
Rtcm::set_DF119(glonass_gnav_eph);
Rtcm::set_DF120(glonass_gnav_eph);
Rtcm::set_DF121(glonass_gnav_eph);
Rtcm::set_DF122(glonass_gnav_eph);
Rtcm::set_DF123(glonass_gnav_eph);
Rtcm::set_DF124(glonass_gnav_eph);
Rtcm::set_DF125(glonass_gnav_eph);
Rtcm::set_DF126(glonass_gnav_eph);
Rtcm::set_DF127(glonass_gnav_eph);
Rtcm::set_DF128(glonass_gnav_eph);
Rtcm::set_DF129(glonass_gnav_eph);
Rtcm::set_DF130(glonass_gnav_eph);
Rtcm::set_DF131(fifth_str_additional_data_ind);
Rtcm::set_DF132(glonass_gnav_utc_model);
Rtcm::set_DF133(glonass_gnav_utc_model);
Rtcm::set_DF134(glonass_gnav_utc_model);
Rtcm::set_DF135(glonass_gnav_utc_model);
Rtcm::set_DF136(glonass_gnav_eph);
std::string data;
data.clear();
data = DF002.to_string() +
DF038.to_string() +
DF040.to_string() +
DF104.to_string() +
DF105.to_string() +
DF106.to_string() +
DF107.to_string() +
DF108.to_string() +
DF109.to_string() +
DF110.to_string() +
DF111.to_string() +
DF112.to_string() +
DF113.to_string() +
DF114.to_string() +
DF115.to_string() +
DF116.to_string() +
DF117.to_string() +
DF118.to_string() +
DF119.to_string() +
DF120.to_string() +
DF121.to_string() +
DF122.to_string() +
DF123.to_string() +
DF124.to_string() +
DF125.to_string() +
DF126.to_string() +
DF127.to_string() +
DF128.to_string() +
DF129.to_string() +
DF130.to_string() +
DF131.to_string() +
DF132.to_string() +
DF133.to_string() +
DF134.to_string() +
DF135.to_string() +
DF136.to_string() +
std::bitset<7>().to_string(); // Reserved bits
if (data.length() != 360)
{
LOG(WARNING) << "Bad-formatted RTCM MT1020 (360 bits expected, found " << data.length() << ")";
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
int Rtcm::read_MT1020(const std::string & message, Glonass_Gnav_Ephemeris & glonass_gnav_eph, Glonass_Gnav_Utc_Model & glonass_gnav_utc_model)
{
// Convert message to binary
std::string message_bin = Rtcm::binary_data_to_bin(message);
int glonass_gnav_alm_health = 0;
int glonass_gnav_alm_health_ind = 0;
int fifth_str_additional_data_ind = 0;
if(!Rtcm::check_CRC(message) )
{
LOG(WARNING) << " Bad CRC detected in RTCM message MT1020";
return 1;
}
unsigned int preamble_length = 8;
unsigned int reserved_field_length = 6;
unsigned int index = preamble_length + reserved_field_length;
unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10)));
index += 10;
if (read_message_length != 45) // 360 bits = 45 bytes
{
LOG(WARNING) << " Message MT1020 seems too long (61 bytes expected, " << read_message_length << " received)";
return 1;
}
// Check than the message number is correct
unsigned int read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12));
index += 12;
if (1020 != read_msg_number)
{
LOG(WARNING) << " This is not a MT1020 message";
return 1;
}
// Fill Gps Ephemeris with message data content
glonass_gnav_eph.i_satellite_slot_number = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6)));
index += 6;
glonass_gnav_eph.i_satellite_freq_channel = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5)) - 7.0);
index += 5;
glonass_gnav_alm_health = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
if(glonass_gnav_alm_health){} //Avoid comiler warning
glonass_gnav_alm_health_ind = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
if(glonass_gnav_alm_health_ind){} //Avoid comiler warning
glonass_gnav_eph.d_P_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2)));
glonass_gnav_eph.d_P_1 = (glonass_gnav_eph.d_P_1+1)*15;
index += 2;
glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 5)))*3600;
index += 5;
glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 6)))*60;
index += 6;
glonass_gnav_eph.d_t_k += static_cast(Rtcm::bin_to_int(message_bin.substr(index, 1)))*30;
index += 1;
glonass_gnav_eph.d_B_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
glonass_gnav_eph.d_P_2 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
glonass_gnav_eph.d_t_b = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 7)))*glonass_gnav_eph.d_P_1*60.0;
index += 7;
// TODO Check for type spec for intS24
glonass_gnav_eph.d_VXn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24)))*TWO_N20;
index += 24;
glonass_gnav_eph.d_Xn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27)))*TWO_N11;
index += 27;
glonass_gnav_eph.d_AXn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))*TWO_N30;
index += 5;
glonass_gnav_eph.d_VYn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24)))*TWO_N20;
index += 24;
glonass_gnav_eph.d_Yn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27)))*TWO_N11;
index += 27;
glonass_gnav_eph.d_AYn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))*TWO_N30;
index += 5;
glonass_gnav_eph.d_VZn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 24)))*TWO_N20;
index += 24;
glonass_gnav_eph.d_Zn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 27)))*TWO_N11;
index += 27;
glonass_gnav_eph.d_AZn = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))*TWO_N30;
index += 5;
glonass_gnav_eph.d_P_3 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
glonass_gnav_eph.d_gamma_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 11)))*TWO_N30;
index += 11;
glonass_gnav_eph.d_P = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2)));
index += 2;
glonass_gnav_eph.d_l3rd_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
glonass_gnav_eph.d_tau_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 22)))* TWO_N30;
index += 22;
glonass_gnav_eph.d_Delta_tau_n = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 5)))* TWO_N30;
index += 5;
glonass_gnav_eph.d_E_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5)));
index += 5;
glonass_gnav_eph.d_P_4 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
glonass_gnav_eph.d_F_T = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 4)));
index += 4;
glonass_gnav_eph.d_N_T = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 11)));
index += 11;
glonass_gnav_eph.d_M = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2)));
index += 2;
fifth_str_additional_data_ind = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
index += 1;
if(fifth_str_additional_data_ind == true)
{
glonass_gnav_utc_model.d_N_A = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 11)));
index += 11;
glonass_gnav_utc_model.d_tau_c = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 32)))* TWO_N31;
index += 32;
glonass_gnav_utc_model.d_N_4 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 5)));
index += 5;
glonass_gnav_utc_model.d_tau_gps = static_cast(Rtcm::bin_to_sint(message_bin.substr(index, 22)))* TWO_N30;
index += 22;
glonass_gnav_eph.d_l5th_n = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
}
return 0;
}
// ********************************************************
//
// MESSAGE TYPE 1029 (UNICODE TEXT STRING)
//
// ********************************************************
std::string Rtcm::print_MT1029(unsigned int ref_id, const Gps_Ephemeris & gps_eph, double obs_time, const std::string & message)
{
unsigned int msg_number = 1029;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF003(ref_id);
Rtcm::set_DF051(gps_eph, obs_time);
Rtcm::set_DF052(gps_eph, obs_time);
unsigned int i = 0;
bool first = true;
std::string text_binary;
for(auto it = message.cbegin(); it != message.cend(); it++)
{
char c = *it;
if(isgraph(c))
{
i++;
first = true;
}
else if(c == ' ')
{
i++;
first = true;
}
else
{
if(!first)
{
i++;
first = true;
}
else
{
first = false;
}
}
std::bitset<8> character = std::bitset<8>(c);
text_binary += character.to_string();
}
std::bitset<7> DF138_ = std::bitset<7>(i);
std::bitset<8> DF139_ = std::bitset<8>(message.length());
std::string data = DF002.to_string() +
DF003.to_string() +
DF051.to_string() +
DF052.to_string() +
DF138_.to_string() +
DF139_.to_string() +
text_binary;
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
// ********************************************************
//
// MESSAGE TYPE 1045 (GALILEO EPHEMERIS)
//
// ********************************************************
std::string Rtcm::print_MT1045(const Galileo_Ephemeris & gal_eph)
{
unsigned int msg_number = 1045;
Rtcm::set_DF002(msg_number);
Rtcm::set_DF252(gal_eph);
Rtcm::set_DF289(gal_eph);
Rtcm::set_DF290(gal_eph);
Rtcm::set_DF291(gal_eph);
Rtcm::set_DF293(gal_eph);
Rtcm::set_DF294(gal_eph);
Rtcm::set_DF295(gal_eph);
Rtcm::set_DF296(gal_eph);
Rtcm::set_DF297(gal_eph);
Rtcm::set_DF298(gal_eph);
Rtcm::set_DF299(gal_eph);
Rtcm::set_DF300(gal_eph);
Rtcm::set_DF301(gal_eph);
Rtcm::set_DF302(gal_eph);
Rtcm::set_DF303(gal_eph);
Rtcm::set_DF304(gal_eph);
Rtcm::set_DF305(gal_eph);
Rtcm::set_DF306(gal_eph);
Rtcm::set_DF307(gal_eph);
Rtcm::set_DF308(gal_eph);
Rtcm::set_DF309(gal_eph);
Rtcm::set_DF310(gal_eph);
Rtcm::set_DF311(gal_eph);
Rtcm::set_DF312(gal_eph);
Rtcm::set_DF314(gal_eph);
Rtcm::set_DF315(gal_eph);
unsigned int seven_zero = 0;
std::bitset<7> DF001_ = std::bitset<7>(seven_zero);
std::string data;
data.clear();
data = DF002.to_string() +
DF252.to_string() +
DF289.to_string() +
DF290.to_string() +
DF291.to_string() +
DF292.to_string() +
DF293.to_string() +
DF294.to_string() +
DF295.to_string() +
DF296.to_string() +
DF297.to_string() +
DF298.to_string() +
DF299.to_string() +
DF300.to_string() +
DF301.to_string() +
DF302.to_string() +
DF303.to_string() +
DF304.to_string() +
DF305.to_string() +
DF306.to_string() +
DF307.to_string() +
DF308.to_string() +
DF309.to_string() +
DF310.to_string() +
DF311.to_string() +
DF312.to_string() +
DF314.to_string() +
DF315.to_string() +
DF001_.to_string();
if (data.length() != 496)
{
LOG(WARNING) << "Bad-formatted RTCM MT1045 (496 bits expected, found " << data.length() << ")";
}
std::string msg = build_message(data);
if(server_is_running)
{
rtcm_message_queue->push(msg);
}
return msg;
}
int Rtcm::read_MT1045(const std::string & message, Galileo_Ephemeris & gal_eph)
{
// Convert message to binary
std::string message_bin = Rtcm::binary_data_to_bin(message);
if(!Rtcm::check_CRC(message) )
{
LOG(WARNING) << " Bad CRC detected in RTCM message MT1045";
return 1;
}
unsigned int preamble_length = 8;
unsigned int reserved_field_length = 6;
unsigned int index = preamble_length + reserved_field_length;
unsigned int read_message_length = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10)));
index += 10;
if (read_message_length != 62)
{
LOG(WARNING) << " Message MT1045 seems too long (62 bytes expected, " << read_message_length << " received)";
return 1;
}
// Check than the message number is correct
unsigned int read_msg_number = Rtcm::bin_to_uint(message_bin.substr(index, 12));
index += 12;
if (1045 != read_msg_number)
{
LOG(WARNING) << " This is not a MT1045 message";
return 1;
}
// Fill Galileo Ephemeris with message data content
gal_eph.i_satellite_PRN = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 6)));
index += 6;
gal_eph.WN_5 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 12)));
index += 12;
gal_eph.IOD_nav_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 10)));
index += 10;
gal_eph.SISA_3 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 8)));
index += 8;
gal_eph.iDot_2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 14))) * iDot_2_LSB;
index += 14;
gal_eph.t0c_4 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 14))) * t0c_4_LSB;
index += 14;
gal_eph.af2_4 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 6))) * af2_4_LSB;
index += 6;
gal_eph.af1_4 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 21))) * af1_4_LSB;
index += 21;
gal_eph.af0_4 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 31))) * af0_4_LSB;
index += 31;
gal_eph.C_rs_3 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_rs_3_LSB;
index += 16;
gal_eph.delta_n_3 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * delta_n_3_LSB;
index += 16;
gal_eph.M0_1 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * M0_1_LSB;
index += 32;
gal_eph.C_uc_3 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_uc_3_LSB;
index += 16;
gal_eph.e_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 32))) * e_1_LSB;
index += 32;
gal_eph.C_us_3 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_us_3_LSB;
index += 16;
gal_eph.A_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 32))) * A_1_LSB_gal;
index += 32;
gal_eph.t0e_1 = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 14))) * t0e_1_LSB;
index += 14;
gal_eph.C_ic_4 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_ic_4_LSB;
index += 16;
gal_eph.OMEGA_0_2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * OMEGA_0_2_LSB;
index += 32;
gal_eph.C_is_4 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_is_4_LSB;
index += 16;
gal_eph.i_0_2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * i_0_2_LSB;
index += 32;
gal_eph.C_rc_3 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 16))) * C_rc_3_LSB;
index += 16;
gal_eph.omega_2 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 32))) * omega_2_LSB;
index += 32;
gal_eph.OMEGA_dot_3 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 24))) * OMEGA_dot_3_LSB;
index += 24;
gal_eph.BGD_E1E5a_5 = static_cast(Rtcm::bin_to_int(message_bin.substr(index, 10)));
index += 10;
gal_eph.E5a_HS = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 2)));
index += 2;
gal_eph.E5a_DVS = static_cast(Rtcm::bin_to_uint(message_bin.substr(index, 1)));
return 0;
}
// **********************************************************************************************
//
// MESSAGE TYPE MSM1 (COMPACT observables)
//
// **********************************************************************************************
std::string Rtcm::print_MSM_1( const Gps_Ephemeris & gps_eph,
const Gps_CNAV_Ephemeris & gps_cnav_eph,
const Galileo_Ephemeris & gal_eph,
const Glonass_Gnav_Ephemeris & glo_gnav_eph,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
unsigned int msg_number = 0;
if(gps_eph.i_satellite_PRN != 0) msg_number = 1071;
if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1071;
if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1081;
if(gal_eph.i_satellite_PRN != 0) msg_number = 1091;
if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0))
{
LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages?
}
if(msg_number == 0)
{
LOG(WARNING) << "Invalid ephemeris provided";
msg_number = 1071;
}
std::string header = Rtcm::get_MSM_header(msg_number,
obs_time,
observables,
ref_id,
clock_steering_indicator,
external_clock_indicator,
smooth_int,
divergence_free,
more_messages);
std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables);
std::string signal_data = Rtcm::get_MSM_1_content_signal_data(observables);
std::string message = build_message(header + sat_data + signal_data);
if(server_is_running)
{
rtcm_message_queue->push(message);
}
return message;
}
std::string Rtcm::get_MSM_header(unsigned int msg_number,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
// Find first element in observables block and define type of message
std::map::const_iterator observables_iter = observables.begin();
std::string sys(observables_iter->second.System, 1);
Rtcm::set_DF002(msg_number);
Rtcm::set_DF003(ref_id);
Rtcm::set_DF393(more_messages);
Rtcm::set_DF409(0); // Issue of Data Station. 0: not utilized
std::bitset<7> DF001_ = std::bitset<7>("0000000");
Rtcm::set_DF411(clock_steering_indicator);
Rtcm::set_DF412(external_clock_indicator);
Rtcm::set_DF417(divergence_free);
Rtcm::set_DF418(smooth_int);
Rtcm::set_DF394(observables);
Rtcm::set_DF395(observables);
std::string header = DF002.to_string() + DF003.to_string();
// GNSS Epoch Time Specific to each constellation
if((sys.compare("R") == 0 ))
{
// GLONASS Epoch Time
Rtcm::set_DF034(obs_time);
header += DF034.to_string();
}
else
{
// GPS, Galileo Epoch Time
Rtcm::set_DF004(obs_time);
header += DF004.to_string();
}
header = header + DF393.to_string() +
DF409.to_string() +
DF001_.to_string() +
DF411.to_string() +
DF417.to_string() +
DF412.to_string() +
DF418.to_string() +
DF394.to_string() +
DF395.to_string() +
Rtcm::set_DF396(observables);
return header;
}
std::string Rtcm::get_MSM_1_content_sat_data(const std::map & observables)
{
std::string sat_data;
sat_data.clear();
Rtcm::set_DF394(observables);
unsigned int num_satellites = DF394.count();
std::vector > observables_vector;
std::map::const_iterator gnss_synchro_iter;
std::vector pos;
std::vector::iterator it;
for(gnss_synchro_iter = observables.cbegin();
gnss_synchro_iter != observables.cend();
gnss_synchro_iter++)
{
it = std::find(pos.begin(), pos.end(), 65 - gnss_synchro_iter->second.PRN);
if(it == pos.end())
{
pos.push_back(65 - gnss_synchro_iter->second.PRN);
observables_vector.push_back(*gnss_synchro_iter);
}
}
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector);
for(unsigned int nsat = 0; nsat < num_satellites; nsat++)
{
Rtcm::set_DF398( ordered_by_PRN_pos.at(nsat).second );
sat_data += DF398.to_string();
}
return sat_data;
}
std::string Rtcm::get_MSM_1_content_signal_data(const std::map & observables)
{
std::string signal_data;
signal_data.clear();
unsigned int Ncells = observables.size();
std::vector > observables_vector;
std::map::const_iterator map_iter;
for(map_iter = observables.cbegin();
map_iter != observables.cend();
map_iter++)
{
observables_vector.push_back(*map_iter);
}
std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector);
std::reverse(ordered_by_signal.begin(), ordered_by_signal.end());
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal);
for(unsigned int cell = 0; cell < Ncells ; cell++)
{
Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second);
signal_data += DF400.to_string();
}
return signal_data;
}
// **********************************************************************************************
//
// MESSAGE TYPE MSM2 (COMPACT PHASERANGES)
//
// **********************************************************************************************
std::string Rtcm::print_MSM_2( const Gps_Ephemeris & gps_eph,
const Gps_CNAV_Ephemeris & gps_cnav_eph,
const Galileo_Ephemeris & gal_eph,
const Glonass_Gnav_Ephemeris & glo_gnav_eph,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
unsigned int msg_number = 0;
if(gps_eph.i_satellite_PRN != 0) msg_number = 1072;
if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1072;
if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1082;
if(gal_eph.i_satellite_PRN != 0) msg_number = 1092;
if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0))
{
LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages?
}
if(msg_number == 0)
{
LOG(WARNING) << "Invalid ephemeris provided";
msg_number = 1072;
}
std::string header = Rtcm::get_MSM_header(msg_number,
obs_time,
observables,
ref_id,
clock_steering_indicator,
external_clock_indicator,
smooth_int,
divergence_free,
more_messages);
std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables);
std::string signal_data = Rtcm::get_MSM_2_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables);
std::string message = build_message(header + sat_data + signal_data);
if(server_is_running)
{
rtcm_message_queue->push(message);
}
return message;
}
std::string Rtcm::get_MSM_2_content_signal_data(const Gps_Ephemeris & ephNAV,
const Gps_CNAV_Ephemeris & ephCNAV,
const Galileo_Ephemeris & ephFNAV,
const Glonass_Gnav_Ephemeris & ephGNAV,
double obs_time,
const std::map & observables)
{
std::string signal_data;
std::string first_data_type;
std::string second_data_type;
std::string third_data_type;
unsigned int Ncells = observables.size();
std::vector > observables_vector;
std::map::const_iterator map_iter;
for(map_iter = observables.cbegin();
map_iter != observables.cend();
map_iter++)
{
observables_vector.push_back(*map_iter);
}
std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector);
std::reverse(ordered_by_signal.begin(), ordered_by_signal.end());
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal);
for(unsigned int cell = 0; cell < Ncells ; cell++)
{
Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second);
first_data_type += DF401.to_string();
second_data_type += DF402.to_string();
third_data_type += DF420.to_string();
}
signal_data = first_data_type + second_data_type + third_data_type;
return signal_data;
}
// **********************************************************************************************
//
// MESSAGE TYPE MSM3 (COMPACT PSEUDORANGES AND PHASERANGES)
//
// **********************************************************************************************
std::string Rtcm::print_MSM_3( const Gps_Ephemeris & gps_eph,
const Gps_CNAV_Ephemeris & gps_cnav_eph,
const Galileo_Ephemeris & gal_eph,
const Glonass_Gnav_Ephemeris & glo_gnav_eph,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
unsigned int msg_number = 0;
if(gps_eph.i_satellite_PRN != 0) msg_number = 1073;
if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1073;
if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1083;
if(gal_eph.i_satellite_PRN != 0) msg_number = 1093;
if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0))
{
LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages?
}
if(msg_number == 0)
{
LOG(WARNING) << "Invalid ephemeris provided";
msg_number = 1073;
}
std::string header = Rtcm::get_MSM_header(msg_number,
obs_time,
observables,
ref_id,
clock_steering_indicator,
external_clock_indicator,
smooth_int,
divergence_free,
more_messages);
std::string sat_data = Rtcm::get_MSM_1_content_sat_data(observables);
std::string signal_data = Rtcm::get_MSM_3_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables);
std::string message = build_message(header + sat_data + signal_data);
if(server_is_running)
{
rtcm_message_queue->push(message);
}
return message;
}
std::string Rtcm::get_MSM_3_content_signal_data(const Gps_Ephemeris & ephNAV,
const Gps_CNAV_Ephemeris & ephCNAV,
const Galileo_Ephemeris & ephFNAV,
const Glonass_Gnav_Ephemeris & ephGNAV,
double obs_time,
const std::map & observables)
{
std::string signal_data;
std::string first_data_type;
std::string second_data_type;
std::string third_data_type;
std::string fourth_data_type;
unsigned int Ncells = observables.size();
std::vector > observables_vector;
std::map::const_iterator map_iter;
for(map_iter = observables.cbegin();
map_iter != observables.cend();
map_iter++)
{
observables_vector.push_back(*map_iter);
}
std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector);
std::reverse(ordered_by_signal.begin(), ordered_by_signal.end());
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal);
for(unsigned int cell = 0; cell < Ncells ; cell++)
{
Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second);
first_data_type += DF400.to_string();
second_data_type += DF401.to_string();
third_data_type += DF402.to_string();
fourth_data_type += DF420.to_string();
}
signal_data = first_data_type + second_data_type + third_data_type + fourth_data_type;
return signal_data;
}
// **********************************************************************************************
//
// MESSAGE TYPE MSM4 (FULL PSEUDORANGES AND PHASERANGES PLUS CNR)
//
// **********************************************************************************************
std::string Rtcm::print_MSM_4( const Gps_Ephemeris & gps_eph,
const Gps_CNAV_Ephemeris & gps_cnav_eph,
const Galileo_Ephemeris & gal_eph,
const Glonass_Gnav_Ephemeris & glo_gnav_eph,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
unsigned int msg_number = 0;
if(gps_eph.i_satellite_PRN != 0) msg_number = 1074;
if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1074;
if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1084;
if(gal_eph.i_satellite_PRN != 0) msg_number = 1094;
if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0))
{
LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages?
}
if(msg_number == 0)
{
LOG(WARNING) << "Invalid ephemeris provided";
msg_number = 1074;
}
std::string header = Rtcm::get_MSM_header(msg_number,
obs_time,
observables,
ref_id,
clock_steering_indicator,
external_clock_indicator,
smooth_int,
divergence_free,
more_messages);
std::string sat_data = Rtcm::get_MSM_4_content_sat_data(observables);
std::string signal_data = Rtcm::get_MSM_4_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables);
std::string message = build_message(header + sat_data + signal_data);
if(server_is_running)
{
rtcm_message_queue->push(message);
}
return message;
}
std::string Rtcm::get_MSM_4_content_sat_data(const std::map & observables)
{
std::string sat_data;
std::string first_data_type;
std::string second_data_type;
Rtcm::set_DF394(observables);
unsigned int num_satellites = DF394.count();
std::vector > observables_vector;
std::map::const_iterator gnss_synchro_iter;
std::vector pos;
std::vector::iterator it;
for(gnss_synchro_iter = observables.cbegin();
gnss_synchro_iter != observables.cend();
gnss_synchro_iter++)
{
it = std::find(pos.begin(), pos.end(), 65 - gnss_synchro_iter->second.PRN);
if(it == pos.end())
{
pos.push_back(65 - gnss_synchro_iter->second.PRN);
observables_vector.push_back(*gnss_synchro_iter);
}
}
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector);
for(unsigned int nsat = 0; nsat < num_satellites; nsat++)
{
Rtcm::set_DF397( ordered_by_PRN_pos.at(nsat).second );
Rtcm::set_DF398( ordered_by_PRN_pos.at(nsat).second );
first_data_type += DF397.to_string();
second_data_type += DF398.to_string();
}
sat_data = first_data_type + second_data_type;
return sat_data;
}
std::string Rtcm::get_MSM_4_content_signal_data(const Gps_Ephemeris & ephNAV,
const Gps_CNAV_Ephemeris & ephCNAV,
const Galileo_Ephemeris & ephFNAV,
const Glonass_Gnav_Ephemeris & ephGNAV,
double obs_time,
const std::map & observables)
{
std::string signal_data;
std::string first_data_type;
std::string second_data_type;
std::string third_data_type;
std::string fourth_data_type;
std::string fifth_data_type;
unsigned int Ncells = observables.size();
std::vector > observables_vector;
std::map::const_iterator map_iter;
for(map_iter = observables.cbegin();
map_iter != observables.cend();
map_iter++)
{
observables_vector.push_back(*map_iter);
}
std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector);
std::reverse(ordered_by_signal.begin(), ordered_by_signal.end());
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal);
for(unsigned int cell = 0; cell < Ncells ; cell++)
{
Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF403(ordered_by_PRN_pos.at( cell ).second);
first_data_type += DF400.to_string();
second_data_type += DF401.to_string();
third_data_type += DF402.to_string();
fourth_data_type += DF420.to_string();
fifth_data_type += DF403.to_string();
}
signal_data = first_data_type + second_data_type + third_data_type + fourth_data_type + fifth_data_type;
return signal_data;
}
// **********************************************************************************************
//
// MESSAGE TYPE MSM5 (FULL PSEUDORANGES, PHASERANGES, PHASERANGERATE PLUS CNR)
//
// **********************************************************************************************
std::string Rtcm::print_MSM_5( const Gps_Ephemeris & gps_eph,
const Gps_CNAV_Ephemeris & gps_cnav_eph,
const Galileo_Ephemeris & gal_eph,
const Glonass_Gnav_Ephemeris & glo_gnav_eph,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
unsigned int msg_number = 0;
if(gps_eph.i_satellite_PRN != 0) msg_number = 1075;
if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1075;
if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1085;
if(gal_eph.i_satellite_PRN != 0) msg_number = 1095;
if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0))
{
LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages?
}
if(msg_number == 0)
{
LOG(WARNING) << "Invalid ephemeris provided";
msg_number = 1075;
}
std::string header = Rtcm::get_MSM_header(msg_number,
obs_time,
observables,
ref_id,
clock_steering_indicator,
external_clock_indicator,
smooth_int,
divergence_free,
more_messages);
std::string sat_data = Rtcm::get_MSM_5_content_sat_data(observables);
std::string signal_data = Rtcm::get_MSM_5_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables);
std::string message = build_message(header + sat_data + signal_data);
if(server_is_running)
{
rtcm_message_queue->push(message);
}
return message;
}
std::string Rtcm::get_MSM_5_content_sat_data(const std::map & observables)
{
std::string sat_data;
std::string first_data_type;
std::string second_data_type;
std::string third_data_type;
std::string fourth_data_type;
Rtcm::set_DF394(observables);
unsigned int num_satellites = DF394.count();
std::vector > observables_vector;
std::map::const_iterator gnss_synchro_iter;
std::vector pos;
std::vector::iterator it;
for(gnss_synchro_iter = observables.cbegin();
gnss_synchro_iter != observables.cend();
gnss_synchro_iter++)
{
it = std::find(pos.begin(), pos.end(), 65 - gnss_synchro_iter->second.PRN);
if(it == pos.end())
{
pos.push_back(65 - gnss_synchro_iter->second.PRN);
observables_vector.push_back(*gnss_synchro_iter);
}
}
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(observables_vector);
for(unsigned int nsat = 0; nsat < num_satellites; nsat++)
{
Rtcm::set_DF397( ordered_by_PRN_pos.at(nsat).second );
Rtcm::set_DF398( ordered_by_PRN_pos.at(nsat).second );
Rtcm::set_DF399( ordered_by_PRN_pos.at(nsat).second );
std::bitset<4> reserved = std::bitset<4>("0000");
first_data_type += DF397.to_string();
second_data_type += reserved.to_string();
third_data_type += DF398.to_string();
fourth_data_type += DF399.to_string();
}
sat_data = first_data_type + second_data_type + third_data_type + fourth_data_type;
return sat_data;
}
std::string Rtcm::get_MSM_5_content_signal_data(const Gps_Ephemeris & ephNAV,
const Gps_CNAV_Ephemeris & ephCNAV,
const Galileo_Ephemeris & ephFNAV,
const Glonass_Gnav_Ephemeris & ephGNAV,
double obs_time,
const std::map & observables)
{
std::string signal_data;
std::string first_data_type;
std::string second_data_type;
std::string third_data_type;
std::string fourth_data_type;
std::string fifth_data_type;
std::string sixth_data_type;
unsigned int Ncells = observables.size();
std::vector > observables_vector;
std::map::const_iterator map_iter;
for(map_iter = observables.cbegin();
map_iter != observables.cend();
map_iter++)
{
observables_vector.push_back(*map_iter);
}
std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector);
std::reverse(ordered_by_signal.begin(), ordered_by_signal.end());
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal);
for(unsigned int cell = 0; cell < Ncells ; cell++)
{
Rtcm::set_DF400(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF401(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF402(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF403(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF404(ordered_by_PRN_pos.at( cell ).second);
first_data_type += DF400.to_string();
second_data_type += DF401.to_string();
third_data_type += DF402.to_string();
fourth_data_type += DF420.to_string();
fifth_data_type += DF403.to_string();
sixth_data_type += DF404.to_string();
}
signal_data = first_data_type + second_data_type + third_data_type + fourth_data_type + fifth_data_type + sixth_data_type;
return signal_data;
}
// **********************************************************************************************
//
// MESSAGE TYPE MSM6 (FULL PSEUDORANGES AND PHASERANGES PLUS CNR, HIGH RESOLUTION)
//
// **********************************************************************************************
std::string Rtcm::print_MSM_6( const Gps_Ephemeris & gps_eph,
const Gps_CNAV_Ephemeris & gps_cnav_eph,
const Galileo_Ephemeris & gal_eph,
const Glonass_Gnav_Ephemeris & glo_gnav_eph,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
unsigned int msg_number = 0;
if(gps_eph.i_satellite_PRN != 0) msg_number = 1076;
if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1076;
if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1086;
if(gal_eph.i_satellite_PRN != 0) msg_number = 1096;
if(((gps_eph.i_satellite_PRN != 0) ||(gps_cnav_eph.i_satellite_PRN != 0) ) && (gal_eph.i_satellite_PRN != 0) && (glo_gnav_eph.i_satellite_PRN != 0))
{
LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages?
}
if(msg_number == 0)
{
LOG(WARNING) << "Invalid ephemeris provided";
msg_number = 1076;
}
std::string header = Rtcm::get_MSM_header(msg_number,
obs_time,
observables,
ref_id,
clock_steering_indicator,
external_clock_indicator,
smooth_int,
divergence_free,
more_messages);
std::string sat_data = Rtcm::get_MSM_4_content_sat_data(observables);
std::string signal_data = Rtcm::get_MSM_6_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables);
std::string message = build_message(header + sat_data + signal_data);
if(server_is_running)
{
rtcm_message_queue->push(message);
}
return message;
}
std::string Rtcm::get_MSM_6_content_signal_data(const Gps_Ephemeris & ephNAV,
const Gps_CNAV_Ephemeris & ephCNAV,
const Galileo_Ephemeris & ephFNAV,
const Glonass_Gnav_Ephemeris & ephGNAV,
double obs_time,
const std::map & observables)
{
std::string signal_data;
std::string first_data_type;
std::string second_data_type;
std::string third_data_type;
std::string fourth_data_type;
std::string fifth_data_type;
unsigned int Ncells = observables.size();
std::vector > observables_vector;
std::map::const_iterator map_iter;
for(map_iter = observables.cbegin();
map_iter != observables.cend();
map_iter++)
{
observables_vector.push_back(*map_iter);
}
std::vector > ordered_by_signal = Rtcm::sort_by_signal(observables_vector);
std::reverse(ordered_by_signal.begin(), ordered_by_signal.end());
std::vector > ordered_by_PRN_pos = Rtcm::sort_by_PRN_mask(ordered_by_signal);
for(unsigned int cell = 0; cell < Ncells ; cell++)
{
Rtcm::set_DF405(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF406(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF407(ephNAV, ephCNAV, ephFNAV, ephGNAV, obs_time, ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF420(ordered_by_PRN_pos.at( cell ).second);
Rtcm::set_DF408(ordered_by_PRN_pos.at( cell ).second);
first_data_type += DF405.to_string();
second_data_type += DF406.to_string();
third_data_type += DF407.to_string();
fourth_data_type += DF420.to_string();
fifth_data_type += DF408.to_string();
}
signal_data = first_data_type + second_data_type + third_data_type + fourth_data_type + fifth_data_type;
return signal_data;
}
// **********************************************************************************************
//
// MESSAGE TYPE MSM7 (FULL PSEUDORANGES, PHASERANGES, PHASERANGERATE AND CNR, HIGH RESOLUTION)
//
// **********************************************************************************************
std::string Rtcm::print_MSM_7( const Gps_Ephemeris & gps_eph,
const Gps_CNAV_Ephemeris & gps_cnav_eph,
const Galileo_Ephemeris & gal_eph,
const Glonass_Gnav_Ephemeris & glo_gnav_eph,
double obs_time,
const std::map & observables,
unsigned int ref_id,
unsigned int clock_steering_indicator,
unsigned int external_clock_indicator,
int smooth_int,
bool divergence_free,
bool more_messages)
{
unsigned int msg_number = 0;
if(gps_eph.i_satellite_PRN != 0) msg_number = 1077;
if(gps_cnav_eph.i_satellite_PRN != 0) msg_number = 1077;
if(glo_gnav_eph.i_satellite_PRN != 0) msg_number = 1087;
if(gal_eph.i_satellite_PRN != 0) msg_number = 1097;
if(((gps_eph.i_satellite_PRN != 0) || (gps_cnav_eph.i_satellite_PRN != 0) ) && (glo_gnav_eph.i_satellite_PRN != 0) && (gal_eph.i_satellite_PRN != 0))
{
LOG(WARNING) << "MSM messages for observables from different systems are not defined"; //print two messages?
}
if(msg_number == 0)
{
LOG(WARNING) << "Invalid ephemeris provided";
msg_number = 1076;
}
std::string header = Rtcm::get_MSM_header(msg_number,
obs_time,
observables,
ref_id,
clock_steering_indicator,
external_clock_indicator,
smooth_int,
divergence_free,
more_messages);
std::string sat_data = Rtcm::get_MSM_5_content_sat_data(observables);
std::string signal_data = Rtcm::get_MSM_7_content_signal_data(gps_eph, gps_cnav_eph, gal_eph, glo_gnav_eph, obs_time, observables);
std::string message = build_message(header + sat_data + signal_data);
if(server_is_running)
{
rtcm_message_queue->push(message);
}
return message;
}
std::string Rtcm::get_MSM_7_content_signal_data(const Gps_Ephemeris & ephNAV,
const Gps_CNAV_Ephemeris & ephCNAV,
const Galileo_Ephemeris & ephFNAV,
const Glonass_Gnav_Ephemeris & ephGNAV,
double obs_time,
const std::map & observables)
{
std::string signal_data;
std::string first_data_type;
std::string second_data_type;
std::string third_data_type;
std::string fourth_data_type;
std::string fifth_data_type;
std::string sixth_data_type;
unsigned int Ncells = observables.size();
std::vector > observables_vector;
std::map