/*! * \file rtcm_printer.cc * \brief Implementation of a RTCM 3.2 printer for GNSS-SDR * This class provides a implementation of a subset of the RTCM Standard 10403.2 * for Differential GNSS Services * * \author Carles Fernandez-Prades, 2014. 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_printer.h" #include // for O_RDWR #include // for tcgetattr #include // for std::reverse #include // for std::stringstream #include // for to_upper_copy #include #include #include #include using google::LogMessage; //DEFINE_string(RTCM_version, "3.2", "Specifies the RTCM Version"); Rtcm_Printer::Rtcm_Printer(std::string filename, bool flag_rtcm_tty_port, std::string rtcm_dump_devname) { rtcm_filename = filename; rtcm_file_descriptor.open(rtcm_filename.c_str(), std::ios::out); if (rtcm_file_descriptor.is_open()) { DLOG(INFO) << "RTCM printer writing on " << rtcm_filename.c_str(); } rtcm_devname = rtcm_dump_devname; if (flag_rtcm_tty_port == true) { rtcm_dev_descriptor = init_serial(rtcm_devname.c_str()); if (rtcm_dev_descriptor != -1) { DLOG(INFO) << "RTCM printer writing on " << rtcm_devname.c_str(); } } else { rtcm_dev_descriptor = -1; } Rtcm_Printer::reset_data_fields(); preamble = std::bitset<8>("11010011"); reserved_field = std::bitset<6>("000000"); } Rtcm_Printer::~Rtcm_Printer() { if (rtcm_file_descriptor.is_open()) { long pos; rtcm_file_descriptor.close(); pos = rtcm_file_descriptor.tellp(); if (pos == 0) { if(remove(rtcm_filename.c_str()) != 0) LOG(INFO) << "Error deleting temporary file"; } } close_serial(); } int Rtcm_Printer::init_serial(std::string serial_device) { /*! * Opens the serial device and sets the default baud rate for a NMEA transmission (9600,8,N,1) */ int fd = 0; struct termios options; long BAUD; long DATABITS; long STOPBITS; long PARITYON; long PARITY; fd = open(serial_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) return fd; // failed to open TTY port if(fcntl(fd, F_SETFL, 0) == -1) LOG(INFO) << "Error enabling direct I/O"; // clear all flags on descriptor, enable direct I/O tcgetattr(fd, &options); // read serial port options BAUD = B9600; //BAUD = B38400; DATABITS = CS8; STOPBITS = 0; PARITYON = 0; PARITY = 0; options.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD; // enable receiver, set 8 bit data, ignore control lines //options.c_cflag |= (CLOCAL | CREAD | CS8); options.c_iflag = IGNPAR; // set the new port options tcsetattr(fd, TCSANOW, &options); return fd; } void Rtcm_Printer::close_serial() { if (rtcm_dev_descriptor != -1) { close(rtcm_dev_descriptor); } } void Rtcm_Printer::reset_data_fields() { //DF001.reset(); DF002.reset(); DF003.reset(); DF004.reset(); DF005.reset(); DF006.reset(); DF007.reset(); DF008.reset(); DF009.reset(); DF010.reset(); DF011.reset(); DF012.reset(); DF013.reset(); DF014.reset(); DF015.reset(); // Contents of GPS Satellite Ephemeris Data, Message Type 1019 DF071.reset(); DF076.reset(); DF077.reset(); DF078.reset(); DF079.reset(); DF081.reset(); DF082.reset(); DF083.reset(); DF084.reset(); DF085.reset(); DF086.reset(); DF087.reset(); DF088.reset(); DF089.reset(); DF090.reset(); DF091.reset(); DF092.reset(); DF093.reset(); DF094.reset(); DF095.reset(); DF096.reset(); DF097.reset(); DF098.reset(); DF099.reset(); DF100.reset(); DF101.reset(); DF102.reset(); DF103.reset(); DF137.reset(); // Contents of Galileo F/NAV Satellite Ephemeris Data, Message Type 1045 DF252.reset(); DF289.reset(); DF290.reset(); DF291.reset(); DF292.reset(); DF293.reset(); DF294.reset(); DF295.reset(); DF296.reset(); DF297.reset(); DF298.reset(); DF299.reset(); DF300.reset(); DF301.reset(); DF302.reset(); DF303.reset(); DF304.reset(); DF305.reset(); DF306.reset(); DF307.reset(); DF308.reset(); DF309.reset(); DF310.reset(); DF311.reset(); DF312.reset(); DF314.reset(); DF315.reset(); } /* 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_Printer::get_M1005_test () { unsigned int m1005 = 1005; unsigned int reference_station_id = 2003; // Max: 4095 long long int ECEF_X = 11141045999; // Resolution 0.0001 m long long int ECEF_Y = -48507297108; // Resolution 0.0001 m long long int ECEF_Z = 39755214643; // Resolution 0.0001 m unsigned int itrf_realization_year = 0; // Reserved std::bitset<1> DF001; DF002 = std::bitset<12>(m1005); DF003 = std::bitset<12>(reference_station_id); DF021 = std::bitset<6>(itrf_realization_year); DF022 = std::bitset<1>("1"); // GPS DF023 = std::bitset<1>("0"); // Glonass DF024 = std::bitset<1>("0"); // Galileo DF141 = std::bitset<1>("0"); // 0: Real, physical reference station DF001 = std::bitset<1>("0"); // Reserved, set to 0 DF025 = std::bitset<38>(ECEF_X); // ECEF-X in 0.0001 m DF142 = std::bitset<1>("0"); // Single Receiver Oscillator Indicator DF026 = std::bitset<38>(ECEF_Y); // ECEF-Y in 0.0001 m DF364 = std::bitset<2>("00"); // Quarter Cycle Indicator DF027 = std::bitset<38>(ECEF_Z); // ECEF-Z in 0.0001 m 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_Printer::print_M1005_test () { std::bitset<152> m1005 = get_M1005_test(); unsigned int msg_length_bits = m1005.to_string().length(); unsigned int msg_length_bytes = std::ceil(static_cast(msg_length_bits) / 8.0); 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 = m1005.to_string() + b; std::string msg_without_crc = preamble.to_string() + reserved_field.to_string() + message_length.to_string() + msg_content; return Rtcm_Printer::add_CRC(msg_without_crc); } std::bitset<122> Rtcm_Printer::get_M1001() { unsigned int m1001 = 1001; unsigned int reference_station_id = 1234; // Max: 4095 DF002 = std::bitset<12>(m1001); DF003 = std::bitset<12>(reference_station_id); //DF004 = std::bitset<30> //DF005 = std::bitset<1> //DF006 = std::bitset<5> DF007 = std::bitset<1>("0"); //DF008 = std::bitset<3> std::bitset<122> fake_msg; fake_msg.reset(); return fake_msg; } void Rtcm_Printer::print_M1001 () { std::bitset<122> m1001 = get_M1001(); unsigned int msg_length_bits = m1001.to_string().length(); unsigned int msg_length_bytes = std::ceil(static_cast(msg_length_bits) / 8.0); 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'); message_length = std::bitset<10>(static_cast(msg_length_bytes)); std::string msg_content = m1001.to_string() + b; std::string msg_without_crc = preamble.to_string() + reserved_field.to_string() + message_length.to_string() + msg_content; std::string message = Rtcm_Printer::add_CRC(msg_without_crc); } std::bitset<138> Rtcm_Printer::get_M1002 () { std::bitset<138> fake_msg; fake_msg.reset(); return fake_msg; } std::bitset<488> Rtcm_Printer::get_M1019 () { std::bitset<488> fake_msg; fake_msg.reset(); return fake_msg; } std::bitset<496> Rtcm_Printer::get_M1045 () { std::bitset<496> fake_msg; fake_msg.reset(); return fake_msg; } std::string Rtcm_Printer::add_CRC (const std::string& message_without_crc) { // ****** Computes Qualcomm CRC-24Q ****** // 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()); 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_hex(complete_message); } std::string Rtcm_Printer::bin_to_hex(const std::string& s) { std::string s_aux; std::stringstream ss; for(int i = 0; i < s.length() - 1; i = i + 32) { s_aux.assign(s, i, 32); std::bitset<32> bs(s_aux); unsigned n = bs.to_ulong(); ss << std::hex << n; } //return ss.str(); return boost::to_upper_copy(ss.str()); }